开发者

Perl: Unexpected match variables when using ?: operator

Trying to untaint some variables in Perl, and the following code works great:

if ($year =~ /^(\d{4})$/) {
        $year = $1;
} else {
        &invalid("year");
}

In the above instance, $1 contains $year if valid. However, when using the ?: operator, $1 contains "1" when valid:

($year =~ /^(\d{4})$/) ? $year = $1 : &invalid("year");

Anyone see where I might be at fault? I'm confused why this is happening. It's only happening on this ma开发者_开发问答chine. Or rather, I have successfully used the ? operator for returning proper match variables for years. I haven't tried this piece of code on any other machine yet.

This is Perl, v5.8.8 built for x86_64-linux-thread-multi


Be careful about precedence here.

Contrast http://codepad.org/vEPnhWfH which works as expected, with http://codepad.org/nXVU5CA7 which does not. Of course, I tweaked the code a little bit to avoid calling invalid, but I suspect this may be at the root of the problem.

In both cases, though $1 contains "2011", so perhaps you should show additional code, as requested in the first comment by mu.

UPDATE

I changed the codepad examples to use the call to &invalid and the error does not show up.

sub invalid {
    print("INVALID\n");
}

sub check_with_if {
    print("Trying with if-statement\n");
    my $year = shift;
    if ($year =~ /^(\d{4})$/) {
        $year = $1;
    } else {
        &invalid($year);
    }
    print("\$1 is $1 and \$year is $year"."\n");
}

sub check_with_conditional {
    print("Trying with conditional expression\n");
    my $year = shift;
    ($year =~ /^(\d{4})$/) ? $year = $1 : &invalid($year);
    print("\$1 is $1 and \$year is $year"."\n");
}

check_with_if("2011");
check_with_conditional("2011");

Output is

Trying with if-statement 
$1 is 2011 and $year is 2011
Trying with conditional expression
$1 is 2011 and $year is 2011

http://codepad.org/z22GMEcn

EDIT 2 Also works on 5.12.3 on the Mac.

I agree with Jonathan that you may have found a bug in 5.8.8 that has been fixed since. If you are incredibly curious you can work your way through the Perl changes, such as:

  • http://search.cpan.org/~jesse/perl-5.14.1/pod/perl5100delta.pod (5.8.8 -> 5.10.0)
  • http://search.cpan.org/~jesse/perl-5.11.1/pod/perl5110delta.pod (5.10.0 -> 5.11.0)
  • http://search.cpan.org/~jesse/perl-5.12.0/pod/perl5120delta.pod (5.10.0 -> 5.12.0)


Damien Conway's Perl Best Practices explains some of the pitfalls of using the match variables $1 and so on, one of them is that:

  • if the regex doesn't match anything, $1 does not become undef, but it preserves its previous value (which of course, in most cases is undef)

My intuition tells me that you have a problem with contexts - your expression might be evaluated in scalar context, thus returning the number of matches when it is valid.

So, I would try rewriting the code like:

($year) = ( $year =~ /^(\d{4})$/) or &invalid("year");


With Perl 5.14.1 (on MacOS X 10.7.1), this script seems to work OK:

use strict;
use warnings;

my $year = "1984";

sub invalid
{
    my($year) = @_;
    print "Invalid year $year\n";
}

if ($year =~ /^(\d{4})$/)
{
    $year = $1;
}
else
{
    &invalid("year");
}


print "Year1: $year\n";

$year = "1984";
($year =~ /^(\d{4})$/) ? $year = $1 : &invalid("year");

print "Year2: $year\n";

It produces:

Year1: 1984
Year2: 1984

If the same script produces a different answer in Perl 5.8.8, then presumably you've hit a bug that has been fixed and an upgrade is in order. If Perl 5.8.8 produces the same answer (as Perl 5.14.1), then you have not yet characterized your problem so that I can understand it and reproduce the issue.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜