Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

IP Filtering RegEx needed

by Anonymous Monk
on Sep 15, 2004 at 14:10 UTC ( #391181=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hey guys, I'm trying to build a regex that will catch any IP based on the following format:
123.145.[146-149].2 or 135.168.[10-115].[0-125] or some combination of the two
I'm iterating through a list of IP's and trying to match them against the above format.

Any suggestions? Can I use the format to build my regex (i.e.):

my $RegEx = qw/123.145.[146-149].2/; print "$IP\n" if ($IP =~ /$RegEx/);

Comment on IP Filtering RegEx needed
Select or Download Code
Re: IP Filtering RegEx needed
by Roger (Parson) on Sep 15, 2004 at 14:22 UTC
    You need to quote the meta characters in the regex with \Q and \E. Otherwise you need to escape the meta-characters (such as [ and .) with backslash (\).

    Here's an example:
    #!/usr/bin/perl -w use strict; my $grp = qr/\[\d+-\d+\]/; for (<DATA>) { print if /\d+\.\d+\.$grp\.(\d+|$grp)/; } __DATA__ 123.145.[146-149].2 135.168.[10-115].[0-125] 135.168.12.[0-125]


    Update:
    Sorry I misread the question. If you are after a single regex to do range checking, you can use the match time interpolation technique.
    #!/usr/bin/perl -w use strict; my $grp = qr/^123\.145\.(\d+)\.(\d+)$(??{ $1 >= 146 && $1 <= 148 ? '' +: 1})/; for (<DATA>) { print if /$grp/; } __DATA__ 123.145.130.3 123.145.146.3 123.145.147.3 123.145.148.3 123.145.149.3

Re: IP Filtering RegEx needed
by dave_the_m (Parson) on Sep 15, 2004 at 14:24 UTC
    It's usually easier to to do the range check outside the regex, eg
    print "$IP\n" if $IP =~ /^135\.168\.(\d+)\.(\d+)$/ and $1 >= 10 and $1 <= 115 and $2 >= 0 and $2 <= 125;

    Dave.

Re: IP Filtering RegEx needed
by Dietz (Curate) on Sep 15, 2004 at 14:29 UTC
    If you only want to match these IP's in the specified range you could use something like this:
    my $regex = qr/(123\.145\.14[6-9]\.2)|(135\.168\.[1-9][0-9][0-5]?\.[0- +9][0-2]?[0-5]?)/o; print "$ip matched\n" if $ip =~ /$regex/;

    Regards
    Dietz

    Update:
    Added code below (see Re^4: IP Filtering RegEx needed)

      $ perl -le '$_="135.168.995.925"; print "Oops" if /135\.168\.[1-9][0-9 +][0-5]?\.[0-9][0-2]?[0-5]?/' Oops

      This is why it's really better to do the range checking outside the regex as others have mentioned.

      Update: As is remarked below, if you're sure you're not going to get bogus input from your data then this may not be an issue. It's just something to be aware of when you consider what solution to use (and to keep in the back of your mind for when something breaks and you get bogus results from something like this and can't figure out why . . . :).

        You're are absolutely right!

        OTOH in which log would you find addresses containing an octet with '995'

        My attempt was just a quick hack to serve the OP and is not fully tested, though I believe it's good enough to don't match other ranges, but I could be incorrect, and maybe I should have stated so :-(

        Thank you!
        Dietz

Re: IP Filtering RegEx needed
by EdwardG (Vicar) on Sep 15, 2004 at 14:34 UTC

    Watch out for those dots! In a RegEx they can mean literally any character.

    Here's a sample that matches either of your IP ranges-

    my @tests = <DATA>; chomp @tests; for my $test (@tests) { if ($test =~ /^123\.145\.14[6789]\.2$/ or ( $test =~ /^135\.168\.(\d\d?\d?)\.(\d\d?\d?)$/ and ( $1 >= 10 and $1 <= 115) and ( $2 >= 0 and $2 <= 125) ) ) { print "YES: $test\n"; } else { print "NO: $test\n"; } } __DATA__ 123.145.147.2 123.145.150.2 135.168.0.1 135.168.10.1 135.168.10.200 999 123.456.178 123.456.789.09 135.168.010.001

    Output:

    YES: 123.145.147.2 NO: 123.145.150.2 NO: 135.168.0.1 YES: 135.168.10.1 NO: 135.168.10.200 NO: 999 NO: 123.456.178 NO: 123.456.789.09 YES: 135.168.010.001

    Notice that the last IP has some numbers starting with 0 - do you want to allow this?

     

Re: IP Filtering RegEx needed
by Random_Walk (Parson) on Sep 15, 2004 at 15:03 UTC

    This is a bit clunky but I think it should do what you want. I am going to see if I can optimise out some cruft.

    #!/usr/local/bin/perl -w use strict; my %ipranges; while (<DATA>) { next if /^\s*$/; last if /END CONFIG/; chomp; my @ranges = map { if (/^\[(\d+)-(\d+)\]$/) {$1, $2} else {$_, $_}} split /\./; $ipranges{$_}=\@ranges; } while (<DATA>) { next if /^\s*$/; chomp; my $ip=$_; RANGES: foreach my $range (keys %ipranges) { my @eatme=@{$ipranges{$range}}; foreach (split /\./, $ip) { my $min = shift @eatme; my $max = shift @eatme; next RANGES unless ($_ >= $min and $_ <= $max) } print "A match of $ip in range $range\n"; } } __DATA__ 123.145.141.2 123.145.[146-149].2 135.168.[10-115].[0-125] END CONFIG 1.2.3.4 123.145.147.2 123.145.147.4 135.168.102.102 __END__ results A match of 123.145.147.2 in range 123.145.[146-149].2 A match of 135.168.102.102 in range 135.168.[10-115].[0-125]

    updated code

    After a little decrufting and improving (or is that obfuscating) the data structure I have this..
    /usr/local/bin/perl -w use strict; my %ranges; while (<DATA>) { next if /^\s*$/; last if /END CONFIG/; chomp; $ranges{$_}=[ map { if (/^\[(\d+)-(\d+)\]$/) {[$1, $2]} else {[$_, $_]}} split /\./]; } while (<DATA>) { next if /^\s*$/; last if /END/; chomp (my $ip=$_); RANGE: foreach my $range (keys %ranges) { my $i=0; foreach (split /\./, $ip) { next RANGE unless ($_ >= $ranges{$range}->[$i]->[0] and $_ <= $ranges{$range}->[$i++]->[1]); } print "$ip\tmatches range $range\n"; } }

    Cheers,
    R.

      Exactly what I was looking for...Thanks!

      Nice, although...

      A match of +135. 168 . 10e+1 .102 in range 135.168.[10-115].[0-125]

       

        Did you cut and paste the entire lot ? Either chop of __END__ onwards or add last if /END/; in the second while loop, say just before the chomp though I don't think this is your problem, error would be different.

        Else did you find some values of IP address or ranges that gave this result, the posted code runs fine for me but I am on perl 5.005_3 so perhaps something in a more modern perl makes it barf, if so I'd love to see ?

        Cheers,
        R.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://391181]
Approved by Roger
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2014-11-28 04:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My preferred Perl binaries come from:














    Results (193 votes), past polls