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

I'm trying to match two kind of lines with one regular expression:
00:04:23:a5:ce:6d > ff:ff:ff:ff:ff:ff, ethertype IPv6 (0x86dd), length + 66: (hlim 255, next-header: UDP (17), length: 12) ::.61701 > ff02::1 +:2:.547: [udp sum ok] dhcp solicit (xid=493907)
and
00:04:23:a5:ce:6d > ff:ff:ff:ff:ff:ff, ethertype IPv6 (0x86dd), length + 66: ::.61701 > ff02::1:2:.547: [udp sum ok] dhcp solicit (xid=493907 +) (len12, hlim 255)
The only difference between the two is that the len and hlim differ in place.
I'm using this regexpression:
$line=~/^(\S+) > (\S+), \S+ IPv6 \S+ \S+ \S+ .* \S+ > \S+\.547: .* dhc +p6 solicit \(xid=(\d+)/
Can anyone tell me what's wrong with it? Thanks!

Replies are listed 'Best First'.
Re: Help on regular expressions
by ikegami (Patriarch) on Sep 21, 2005 at 14:23 UTC

    Seems to me the following would do the trick:

    $line=~/^(\S+) [ ] > [ ] (\S+), .* IPv6 .* \.547 .* xid=(\d+)/x;
Re: Help on regular expressions
by goldclaw (Scribe) on Sep 21, 2005 at 14:54 UTC
    I assume the 6 in dhcp6 in your regexp is a typo you introduced while posting. Other than that, did you notice how many fields are between IPv6 and > in your second line? How many fields do you have in your regexp? Otherwise I would also recommend using ".*?" instead of ".*". Unless you really know what you do, that is usually what you intend. (.*? means match a sequence of any charachters, but as few as possible...) gc
Re: Help on regular expressions
by izut (Chaplain) on Sep 21, 2005 at 14:29 UTC
    I see you don't need anything between ff:ff:ff:ff:ff:ff and xid, so this works:
    my $line = "00:04:23:a5:ce:6d > ff:ff:ff:ff:ff:ff, ethertype IPv6 (0x8 +6dd), length 66: ::.61701 > ff02::1:2:.547: [udp sum ok] dhcp solicit + (xid=493907) (len12, hlim 255)"; my @match = $line =~ /^(\S+) > (\S+),.*IPv6.*\.547:\.*xid=(\d+)/; print "@match\n";
    Update: You want to match IPv6 and .547, haven't read that.


    Igor S. Lopes - izut
    surrender to perl. your code, your rules.

      Hi,

      You might want to use the \\x trick:

      #!/usr/bin/perl use strict; use warnings; my $data; $data = '00:04:23:a5:ce:6d > ff:ff:ff:ff:ff:ff, ethertype IPv6 (0x86dd +), length 66: (hlim 255, next-header: UDP (17), length: 12) ::.61701 +> ff02::1:2:.547: [udp sum ok] dhcp solicit (xid=493907)'; if ($data =~ /^ (\S+)\s # i need this one \>\s (\S+),\s # this one as well \S+\sIPv6\s \( \S+ \),\s\S+\s\d+\:\s \( hlim\s\d+,\s next-header:\s\S+\s\(\d+\),\s length:\s\d+ \)\s (\S+)\s # just as this one \>\s (\S+)\s # this one \[udp\ssum\sok\]\sdhcp\ssolicit\s \( \S+\= (\d+) # and the final number \) /x) { print ">$1<\n"; print ">$2<\n"; print ">$3<\n"; print ">$4<\n"; print ">$5<\n"; }

      It makes the regex a little easier to understand.

      --
      if ( 1 ) { $postman->ring() for (1..2); }