tags:

views:

150

answers:

2

I'm having perl regex matching problems with a network script I have, I've managed to put the behaviour in a small snippet.

Take this Perl snippet for Perl 5.10.0 in Debian:

#!/usr/bin/perl
use warnings;
use strict;

my $line = "Version: 0\r\n";
my($version) = $line =~ m/^Version:(\s\d+)\r\n$/;
print "1st failed \n" if not $version; 
($version) = $line =~ m/^Version:\s(\d+)\r\n$/;
print "2nd failed \n" if not $version; 
($version) = $line =~ m/^Version:\ (\d+)\r\n$/;
print "3th failed \n" if not $version;

With this output:

2nd failed
3th failed

Apparently the only difference between 1st and 2nd is moving the space out of the extracted pattern, which in theory shouldn't modify the regex at all, just the returned part.

I don't understand why 2nd and 3th don't work exactly as the first one.

EDIT: If you remove the parentheses in $version is not the same script, you don't get the matched result, you get the boolean result of the op, to get the matched result you need to receive it in a unary(only one string to match) tuple.

+12  A: 

The problem is that you're testing for boolean true, because in the latter two cases you're extracting a string value that's false (string '0'). Try this:

$line = "Version: 0\r\n";
my $version;
($version) = $line =~ m/^Version:(\s\d+)\r\n$/;
print "1st failed \n" unless defined $version;
($version) = $line =~ m/^Version:\s(\d+)\r\n$/;
print "2nd failed \n" unless defined $version;
($version) = $line =~ m/^Version:\ (\d+)\r\n$/;
print "3th failed \n" unless defined $version;
chaos
You are definitely right, that wouldn't happen with "Version: 1", the matched pattern is string "0", which has a boolean result of false. How didn't I notice that before? :|
Arkaitz Jimenez
You probably didn't notice because the first match also has a `0`. The difference is that the first match captures `[ ]0`, and the presence of the empty space causes *that* string to evaluate as true. This is why I didn't see it right away, at least.
Telemachus
" `print "failed\n" unless ($version) = $line =~ ...` " might also work
Brad Gilbert
+2  A: 

You're not testing the match operator. If you want to see if a match fails, test the match:

 if( $line =~ m/(...)/ ) {
    $version = $1;
    }

You can at least check that while debugging to narrow the problem to the part that is failing.

Working with different data, like:

 Version: 1\r\n

would have shown you different behavior where you might have noticed that if failed only when the version was 0. That might have lit some light bulbs in your head :)

brian d foy