Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw

Match a Range of IP's

by Dru (Hermit)
on Sep 30, 2004 at 16:05 UTC ( #395385=perlquestion: print w/replies, xml ) Need Help??

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


My apologies if this has already been answered. I've searched using Super Search, but I don't think I'm giving it what it wants.

What I thought would turn out to be a fairly easy match, has got me pulling my hair out. As you can see from the below, I'm trying to match any address between 192.168.1.x - 192.168.99.x, but the only three it will match is:
Even if I change the range to 20-99.
use warnings; use strict; while (<DATA>){ print "$_\n" if /192\.168\.[1-99]\.\d+/g; } __DATA__

Replies are listed 'Best First'.
Re: Match a Range of IP's
by conrad (Beadle) on Sep 30, 2004 at 16:15 UTC
    [1-99] is a character range, not a number range, so it'll match 1 .. 9 or 9 (i.e. it's the same as [1-9]).

    One solution is to use [1-9]\d? instead, which will match 1 .. 9 and any two-digit number (but if you ever get IP addresses of the form "001" this will fail).

    A better option would be to use (\d+) and add " && $1 >= 1 && $1 <= 99" to the end of the line; bear in mind that that will run into trouble if you have multiple IP addresses per line because of your /g though...

Re: Match a Range of IP's
by bpphillips (Friar) on Sep 30, 2004 at 16:13 UTC
    your [1-99] really means match only one character [1-9] (you can't do ranges on two-digit numbers). You need this:
    while (<DATA>){ print "$_\n" if m/^192\.168\.[1-9][0-9]?\.\d+$/; }
Re: Match a Range of IP's
by Zaxo (Archbishop) on Sep 30, 2004 at 16:21 UTC

    The [1-99] doesn't do what you think. It is a character class which will match a single digit in the range one to nine. That corresponds to what you see.

    You can match and test with

    while (<DATA>) { print if /^192\.168\.(\d{1,3})\.(\d{1,3})\b/ and $1 > 0 and $1 < 100 and $2 < 256; }
    I like to do this kind of thing with IP numbers from Socket::inet_aton(), using bitwise ops, but that isn't such an advantage where netmasks don't correspond to the ranges.

    After Compline,

Re: Match a Range of IP's
by DrHyde (Prior) on Sep 30, 2004 at 16:56 UTC
    Check out Net::CIDR. You want the range2cidr and cidrlookup functions.
Re: Match a Range of IP's
by SpanishInquisition (Pilgrim) on Sep 30, 2004 at 17:26 UTC

    Regexp::Common::net looks good. See if it's valid and then check the individual octets once you parse it.

Re: Match a Range of IP's
by runrig (Abbot) on Sep 30, 2004 at 18:13 UTC
    If I understand correctly, you just want:
    use Socket qw(inet_aton); my $lower = inet_aton(""); my $upper = inet_aton(""); while (<DATA>) { chomp; my $ip = inet_aton($_); print "$_\n" if $lower le $ip and $ip le $upper; }
Re: Match a Range of IP's
by lhoward (Vicar) on Sep 30, 2004 at 18:22 UTC
    IMHO, the right way to do this is to convert all the IPs to integers and compare those. Comparing with a RE will work for most common ones, but trying to determine if is betwen and is not well suited for a regular expression.
    if((ip2int($iplow)<=ip2int($ip))\ &&(ip2int($ip) <=ip2int($iphigh))){ #... } sub ip2int{ my $ip=shift; my @s=split /\./,$ip return $s[3]+($s[2]+($s[1]+$s[0]*256)*256)*256; }
Re: Match a Range of IP's
by si_lence (Deacon) on Sep 30, 2004 at 16:18 UTC

    You are using a character class in your match.
    [1-99] means a "1" to "9" and excatly one of it.

    To select only one or two digit number use somethin like
    print "$_\n" if /192\.168\.\d\d?\.\d+/g
    si_lence Update: bpphillips is right with his answer (shame on me!), so I changed the description.
    At least the regex was ok ;-)
      actually, within a character class, a "-" character indicates a range unless it's at the beginning or the end of the character class
Re: Match a Range of IP's
by fokat (Deacon) on Sep 30, 2004 at 23:18 UTC

    Hi there:

    This is a task for NetAddr::IP...

    perl -MNetAddr::IP -ne 'print "$_ match\n" if NetAddr::IP->new("192.168.1/24")->contains(NetAddr::IP->new($_))'

    Best regards

    -lem, but some call me fokat

      Except that the CIDR address you have doesn't match the OP's desired range (, so he'd have to run your code up to 99 times to see if the address is in that range. Or just another way (not tested):
      use Net::CIDR::Lite; my $range = Net::CIDR::Lite->new(""); while (<DATA>) { chomp; print "$_\n" if $range->find($_); }
Re: Match a Range of IP's
by Dru (Hermit) on Sep 30, 2004 at 18:02 UTC

    Thank you everyone. Alot of good suggestions. I'll have to check each one of them out.
Re: Match a Range of IP's
by TedPride (Priest) on Oct 01, 2004 at 09:42 UTC
    while (<DATA>) { print if /^192.168.[1-9]\d?.([1-9]\d?\d?)$/ && $1 < 256; }
    1-99 is either one or two digits, with the first digit always being 1 or greater. Then you have to check for a valid 4th pair, which means 1-3 digits with the first being at least 1 and the whole thing being less than 256.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://395385]
Approved by Zaxo
Front-paged by DrHyde
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (6)
As of 2021-04-22 14:44 GMT
Find Nodes?
    Voting Booth?

    No recent polls found