truptivk has asked for the wisdom of the Perl Monks concerning the following question:

Hello all,

I've been racking my brains over this for the past 2 days and I cannot figure out what is the problem with my code.

I'd really appreciate it if someone could help me. Let me explain the problem before I paste my code here:

I have written an SNMP trap handler which should write the traps received into 2 different flat files, based on the source of the trap. I have this information in a config file that it reads from. Once I've read it I store it in <ip>,<server> format in an array. When I actually receive the trap, I loop through the array and find the IP using reg exp. Now, herein lies the problem: it doesn't match! I've printed both separately, and they are exactly same. So why wouldn't they match? Below is the code:

my $configFile = "servers.conf"; open (DAT, $configFile); my @fileContents = <DAT>; close DAT; my $str; my @allServers; my @bigArray; foreach $str (@fileContents) { if ($str =~ /^\w/) { push (@allServers, $str); } } my $size = scalar(@allServers); my %hashArray; foreach $str (@allServers) { my ($server, $ip) = split ("=", $str); $ip =~ s/^\s+//; $ip =~ s/\s+$//; push (@bigArray, $ip . "," . $server); $hashArray{$ip} = $server; } my ($key, $value, $idx); foreach $str (@bigArray) { print $str . "\n"; # This prints all values correctly } #while (($key, $value) = each (%hashArray)) { # print LOG "$key-$value\n"; #} # above while statement too prints all correctly my $var; # Read the trap info... my $trapInfo = TrapInfo->new(); # simply creates a new object with hos +tname, ip address and var binds print LOG "TrapInfo ipAddr:" . $trapInfo->ipAddress . "--\n"; $var = $trapInfo->ipAddress; ## Please note that following part of code (foreach, if ## exists, while) doesn't work ## It doesn't give any error; simply says no match foreach $str (@bigArray) { print LOG "$str\n"; if ($str eq $var) { print "IP address matched. Proceed to log trap!\n"; last; } else { print "Match not found.\n"; } } print "After for\n"; if (exists ($hashArray{$trapInfo->ipAddress})) { print $trapInfo->ipAddress . " exists!\n"; } while (($key, $value) = each (%hashArray)) { print "KEY: $key--\n"; print "TrapInfo ipAddr: " . $trapInfo->ipAddress . "--\n"; if ($key eq $trapInfo->ipAddress) { print "IP Matches!\n"; } }
I'd be thankful if you could help me find where is the problem :)

Replies are listed 'Best First'.
Re: Regular expression match in code
by moritz (Cardinal) on May 12, 2010 at 08:22 UTC
    In the title of your node you mention a regular expression, but in the code you write
    if ($str eq $var)

    Which is not a regex match, but an exact string comparison.

    I'd also advise you to use strict; use warnings; in your code, and post code that we can actually run (ie not containing references to config files we don't know about, modules we don't have access to etc.), and reduce it to the part that's actually relevant.

    You can use Data::Dumper to inspect your data structures.

      Oops, my bad. I did use regular expression first, because I'd be comparing IP address from trap to values in an array in format <ip address>,<server>. So I had used:
      if ($str =~ /^$var/)
      which didn't work either. I'm already using  use strict; use warnings;. I'm again pasting code that one can run:
      use strict; use warnings; my %hashArray; my $str; my @bigArray; # Adding to an array in format <ip,server> push (@bigArray, "62.40.40.10,ServerOne"); push (@bigArray, "62.40.40.20,ServerTwo"); push (@bigArray, "62.40.40.30,ServerThree"); # Adding to hash $hashArray{"62.40.40.10"} = "ServerOne"; $hashArray{"62.40.40.20"} = "ServerTwo"; $hashArray{"62.40.40.30"} = "ServerThree"; my ($key, $value, $idx); foreach $str (@bigArray) { print $str . "\n"; # This prints all values correctly } while (($key, $value) = each (%hashArray)) { print "$key-$value\n"; } # above while statement too prints all correctly my $var = "62.40.40.30"; print "var: $var\n"; ## Please note that following part of code (foreach, if ## exists, while) doesn't work ## It doesn't give any error; simply says no match foreach $str (@bigArray) { print "$str\n"; if ($str =~ /^$var/) { print "IP address matched. Proceed to log trap!\n"; last; } else { print "Match not found.\n"; } } print "After for\n"; if (exists ($hashArray{$var})) { print $var . " exists in hash!\n"; } while (($key, $value) = each (%hashArray)) { print "KEY: $key\n"; if ($key eq $var) { print "IP Matches!\n"; } }
      I hope this helps... Thanks.
        my $var = "62.40.40.30"; print "var: $var\n"; ## Please note that following part of code (foreach, if ## exists, while) doesn't work ## It doesn't give any error; simply says no match foreach $str (@bigArray) { print "$str\n"; if ($str =~ /^$var/) { print "IP address matched. Proceed to log trap!\n"; last; } else { print "Match not found.\n"; } }

        You iterate over all values in the array. Since one of the items in the array matches the regex, you get one line of output saying IP address matched. Proceed to log trap, and for all items before the match you get the output that no match was found.

        If you don't want that output even though you can match later on, then don't print it. Only print it if the iteration is finished, and you didn't find any matches.

        if (exists ($hashArray{$var})) { print $var . " exists in hash!\n"; } while (($key, $value) = each (%hashArray)) { print "KEY: $key\n"; if ($key eq $var) { print "IP Matches!\n"; } }

        A hash is a better approach to what you try to do, but you do it overly complicated. Instead of iterating over it, you can get the value straigt out of the hash:

        if (exists ($hashArray{$var})){ print "$var exists in the hash.\n"; print "Its value is $hashArray{$var}\n"; }

        Whenever you iterate over a hash to see if the key is in there, you're doing something wrong.

        So with all three methods you actually find the IP you are looking for (and using the hash access is the easiest and most straight forward).

        Perl 6 - links to (nearly) everything that is Perl 6.
Re: Regular expression match in code
by roboticus (Chancellor) on May 12, 2010 at 10:59 UTC

    truptivk:

    A few notes:

    • On line 17, you needn't use the scalar operator on the array as you're assigning to a scalar already.
    • You could simplify the first section of code by combining loops and removing unnecessary temporary variables, something like:
    my $configFile = "servers.conf"; my (@allServers, @bigArray); # Process file line by line rather than reading all lines into an arra +y # and iterating over the array open (DAT, $configFile); while (my $str = <DAT>) { # the action of your first loop: next if $str =~ /^\w/; # the action of your second loop: my ($server, $ip) = split ("=", $str); $ip =~ s/^\s+//; $ip =~ s/\s+$//; push (@bigArray, $ip . "," . $server); $hashArray{$ip} = $server; } close DAT; my $size = @allServers;

    ...roboticus