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

Hello monks,

Can someone please help me understand why this is not working correctly. It is still matching the ip's that I tell it not to.
use warnings; my $file = 'd:\temp\tcp.txt'; my $ignore = qr(192\.168\.188\.3|192\.168\.11\.141|192\.168\.140\.110 |192\.168\.186\.192|192\.168\.186\.166|192\.168\.139\.50 |192\.168\.139\.198|192\.168\.132\.101); open (FILE, $file) or die "Can not open $file: $!\n"; while (<FILE>){ ($src) = (split /;/)[10]; print if ($src !~ /$ignore/); } close FILE

Replies are listed 'Best First'.
Re: Not Matching String is Matching
by Mr. Muskrat (Canon) on Aug 16, 2003 at 14:35 UTC

    Check your file and ensure that the ip address is actually in the eleventh semicolon delimited field. If not then $src will not contain the ip address.

    This snippet skips them just fine.

    use strict; use warnings; my $ignore = qr(192\.168\.188\.3|192\.168\.11\.141|192\.168\.140\.110| +192\.168\.186\.192|192\.168\.186\.166|192\.168\.139\.50|192\.168\.139 +\.198|192\.168\.132\.101); while (<DATA>){ print if ($_ !~ /$ignore/); } __DATA__ 192.168.188.3 192.168.11.141 192.168.140.110 192.168.186.192 192.168.186.166 192.168.139.50 192.168.139.198 192.168.132.101 192.168.188.4 192.168.11.142 192.168.140.111 192.168.186.193 192.168.186.167 192.168.139.51 192.168.139.199 192.168.132.102

    Update: Aha! The qr needs the ip addresses all on one line. You have added whitespace in yours.

      Thanks, I figured it out. Something to do with vim and the temp files it makes while editing. Perl was executing one of the temp files rather then the file I thought it was. The above works now(with the whitespace removed of course).

      -Dru
Re: Not Matching String is Matching
by cchampion (Curate) on Aug 16, 2003 at 15:20 UTC

    Mr. Muskrat has found the immediate solution. For your next attempt, let me suggest some improvement in your code, so that it becomes more readable and easier to maintain.

    my @ips = (qw( 192.168.188.3 192.168.11.141 192.168.140.110 192.168.186.192 192.168.186.166 192.168.139.50 192.168.139.198 192.168.132.101 )); my $ignore = join "|", @ips; while (<FILE>){ print unless /$ignore/; } # ----------------------- sub ignore { my $ip = shift; for (@ips) { return 1 if $ip =~ $_ } return 0; } while (<FILE>) { print unless ignore($_) }

    The first method creates a regular expression from an array. You can add to an array (or delete) much easier than editing such a complicated regex.

    The second example uses a subroutine that, depending on the number of your IPs to ignore, can be much quicker than a regex with alternation.

    HTH

      Read `perldoc -f quotemeta', it's kind of important (especially since . matches any character -- I am aware that the incoming ip may be a valid ip or whatnot, but the lesson here is that you're dealing with patterns, intentionally or not).

      MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
      I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
      ** The third rule of perl club is a statement of fact: pod is sexy.

Re: Not Matching String is Matching
by antirice (Priest) on Aug 16, 2003 at 20:12 UTC

    I don't know if you were looking to block more than one ip address with 192.168.188.3, since it also blocks addresses 192.168.188.30 through 192.168.188.33. I encountered this problem some time back and as such am offering my solution:

    my @ips_to_ignore = qw( 192.168.188.3 192.168.11.141 192.168.140.110 ); my $ignore = join "|",map(qr(\Q$_\E),@ips_to_ignore); $ignore = qr[^(?:$ignore)$]; while (<DATA>){ chomp; print if ($_ !~ /$ignore/); } __DATA__ 192.168.188.3 192.168.11.141 192.168.140.110 192.168.188.33 192.168.187.12 ---output: 192.168.188.33 192.168.187.12

    Hope this helps.

    antirice    
    The first rule of Perl club is - use Perl
    The
    ith rule of Perl club is - follow rule i - 1 for i > 1

Re: Not Matching String is Matching
by NetWallah (Canon) on Aug 16, 2003 at 19:06 UTC
    Mr. Muskrat has made some valid coding suggestions.
    I would suggest using GREP as in the following code to make the IP searching easier on the eye, and possibly faster ..
    my @ips = (qw( 192.168.188.3 192.168.11.141 192.168.140.110 192.168.186.192 192.168.186.166 192.168.139.50 192.168.139.198 192.168.132.101 )); while (<FILE>){ print unless grep(/^$_$/,@ips) > 0; }

      Not very efficient. grep will always loop through all the items every time, even after the wanted element is found.

      It's better using a loop from where you exit when the item is found.

Re: Not Matching String is Matching
by halley (Prior) on Aug 18, 2003 at 13:40 UTC
    One, for long hand-authored regexen like this, try using the /x modifier. It would avoid the whitespace error and make your example easier to read as well.
    my $ignore = qr( 192\.168\.188\.3 | 192\.168\.11\.141 | 192\.168\.140\.110 | 192\.168\.186\.192 | 192\.168\.186\.166 | 192\.168\.139\.50 | 192\.168\.139\.198 | 192\.168\.132\.101 )x ;
    Two, build your regexp from a data table. This gives the opportunity to use modules like Regex::PreSuf to optimize long lists. Think of all the time wasted in backtracking on the "192.168." part over and over.
    use Regex::PreSuf; my @ignore = qw( 192.168.188.3 192.168.11.141 192.168.140.110 192.168.186.192 192.168.186.166 192.168.139.50 192.168.139.198 192.168.132.101 ); my $ignorex = presuf( map { s|\.|\\.|g } @ignore );
    Lastly, now that the list of ignored IPs is really a list, it can come from a configuration file instead of from the script itself.

    --
    [ e d @ h a l l e y . c c ]