Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Matching an IP address

by bort13 (Novice)
on Aug 02, 2000 at 00:41 UTC ( [id://25584]=CUFP: print w/replies, xml ) Need Help??

This is a regex I thought up to match an IP address, allowing only 1-255 in the octets. Are there better/briefer ways of doing this?
m/(([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.){3}([01]?[0-9]?[0-9]|2[0-4 +][0-9]|25[0-5])/

Replies are listed 'Best First'.
RE: Matching an IP address
by knight (Friar) on Aug 02, 2000 at 02:57 UTC
    Since it hasn't been mentioned:

    There's a Net::IPv4Addr module available on CPAN that parses IP addresses and checks legality. It'll also handle addr+netmask pairs like "11.22.33.44/24" or "11.22.33.44/255.255.255.0". The relevant snippet to extract a legal address would be:
    use Net::IPv4Addr qw( :all ); if ($ip = ipv4_checkip($str)) { # do something }
    Unfortunately, most of the other useful-looking methods croak instead of returning undef on failure, so the documentation says you have eval 'em to handle strings with malformed addresses...
RE: Matching an IP address
by BlueLines (Hermit) on Aug 02, 2000 at 00:58 UTC
    well, there's two ways i know of to go about this.

    1) The regex from MRE :
    ^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\. ([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])

    2) This is a pain in the ass to write out, so if i'm only going to be matching once, i'll sacrifice speed for readability:

    sub validip { my ($ip)=@_; my $x; foreach ($ip=~/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/){ $x++ if(($_>=0)&&($_<=255)); } return($x==4); }


    BlueLines

    Disclaimer: This post may contain inaccurate information, be habit forming, cause atomic warfare between peaceful countries, speed up male pattern baldness, interfere with your cable reception, exile you from certain third world countries, ruin your marriage, and generally spoil your day. No batteries included, no strings attached, your mileage may vary.
RE: Matching an IP address
by tye (Sage) on Aug 02, 2000 at 00:59 UTC
    4 == grep {$_<256} /^(\d+)[.](\d+)[.](\d+)[.](\d+)$/

    Note that 0 is a valid value (unlike certain Microsoft programers thought). 10.0.0.1 is a perfectly fine IP address, for example. You can "golf" this by swapping \. for [.] but I think that mostly just makes it harder to read.

    Also note that you might want to outlaw leading zeros since some C programs will incorrectly interpret 10.011.012.013 as containing 3 octal values and won't allow 10.08.09.10 since "08" and "09" aren't valid octal numbers.

    4 == grep {$_<256&&!/^0\d/} /^(\d+)[.](\d+)[.](\d+)[.](\d+)$/
      just outta curiosity, since the only check for a match is a number less than 256, wouldn't something like -1003.4.-23.0 match?

      BlueLines

      Disclaimer: This post may contain inaccurate information, be habit forming, cause atomic warfare between peaceful countries, speed up male pattern baldness, interfere with your cable reception, exile you from certain third world countries, ruin your marriage, and generally spoil your day. No batteries included, no strings attached, your mileage may vary.

        No, because "-" is not a digit and the regex only matches digits. When I first typed the code in, I also checked for -1<$_, but later I realized that wasn't needed. Here is another try:

        1111==join"",map{/^\d+$/&&$_<256&&!/^0\d/?1:2}split/[.]/

        Update: I played about 8 rounds of golf on this before posting and managed to drop ,$_,-1, so the above doesn't reject trailing dots.

RE: Matching an IP address
by young perlhopper (Scribe) on Aug 02, 2000 at 00:55 UTC
    Are you sure you want to allow 0 as the first character? Or three 0's as the first octet? IP addresses don't really lend themselves to regular expressions. If you really want to check for correctness i'd do something like this:

    foreach $octet (split /\./, $ipaddr) { # # check each octet here (numerically, not with # a regex!), i've gotta jet # or i'd write it myself # }
    Okay, okay, it ain't briefer, but it will probably enforce something more like an actual IP address.

    Then again, if you are just trying to pick out IP addresses in text, you might be alright with your regex... You won't find strings like '304.00.3.999' very often in text files.

    Hope this helps,
    Mark

      Why exclude 0.0.0.0?
        I didn't explicitly say that you should... i was just pointing out that his regex looks like it would allow:

        023.45.34.2
        000.34.23.2
        etc, etc...

        Thanks for pointing that out though, i wasn't terribly clear... -Mark mlogan@ccs.neu.edu

Less regex
by gryng (Hermit) on Aug 02, 2000 at 00:56 UTC
    If I'm not restricted to an regex:
    my $ans = 1; my $cnt = 0; for (map {$cnt++ < 4 and $_=~/[0-9]+/ and $_ >= 0 and $_ <= 255 ? 1 : 0} split /\./, $ip) {$ans &= $_};
    Not super pretty, nor fast. But TIMTOWDI, as they say.

    -Gryn

RE: Matching an IP address
by Fastolfe (Vicar) on Aug 02, 2000 at 01:03 UTC
    Assuming you want to stick to regular expressions, for readability's sake you might want to do this:
    $pattern = '[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]'; /(?:(${pattern})\.){3}($pattern)/; # "$1.$2.$3.$4" = IP if matched
    Due the complexity, though, it would probably be tons more efficient to do as other posters suggest and simply loop through the 4 octets:
    sub get_octets { my @octets = split(/\./, shift); return unless @octets == 4; foreach (@octets) { $_ += 0; # Perhaps unnecessary, but forces the "octet" to be + numeric or zero return unless $_ >= 0 && $_ <= 255; } return @octets; }
RE: Matching an IP address
by ncw (Friar) on Aug 16, 2000 at 00:11 UTC
    This is what I came up with (lifted out of a bit of production code).

    die "Bad IP address '$ip'\n" unless $ip && $ip =~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/ && !grep { $_ < 0 || $_ > 255 } split(/\./, $ip);

    Perhaps not the most elegant solution but readable and tested!

      Hmm.. A small issue: Your code allows IP addresses that contain "255" in an octet, or "0" as the last octet, which isn't bad if you're trying to match subnets or broadcasts but won't work perfectly for hosts. Subtle, but how about:
      unless ($get && $get =~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[1-9]{1,3}$/ && !grep { $_ < 0 || $_ > 254 } split(/\./, $get) ) { print "MYSTIFYING: invalid target specified\n"; exit +(-1);}

      Signature void where prohibited by law.

        Sorry, but 255 and 0 are both valid values for octets. Not that you aren't the first person to make that mistake. Part of the installation process for WinNT doesn't allow 0 octets, which caused us interesting problems. For example, 11.0.255.1 is a perfectly valid IP address. Now you could play lots of games with determining which values are valid for the first octet and/or require that the netmask be passed in and use that to do a proper check... But I don't think such is at all worth it.

                - tye (but my friends call me "Tye")

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://25584]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (2)
As of 2024-04-25 06:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found