Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
456 views
in Technique[技术] by (71.8m points)

Perl regex wrongfully evaluating expressions

I have the following perl code with a string that I'm needing to check against several cases in order to decide what to do with it. None of them work. Code looks like this:

my $param = "02 1999";
my @months = qw(january february march april may june july august september october november december);

my $white = /^s*$/; #check if all whitespace
my $singleyear = /^d{2,4}$/; #check if 2-4 digits
my $nummonth = /^d{1,2}sd{1,4}$/; #check if 1-2 digits then 1-4

if ($param =~ $white) {
    my($day, $month, $year)=(localtime)[3,4,5];
    my $monthname = $months[$month]; 
    print "$monthname $year
";
}
if ($param =~ $singleyear) {
    print "$param
";
}
if ($param =~ $nummonth) {
    my $monthnumber = $param =~ /^d{1,2}/; #grabs the number at the front of the string
    my $monthstring = $months[$monthnumber]; 
    my $yearnumber = $param =~ /(d{1,4})$/; #grab second number, it does this wrong
    print "$monthstring $yearnumber
";
}

Given the above, the output should simply be:

february 1999

Instead, the output is:

3 118
02 1999
february 1 #this only grabbed the first digit for some reason.

So ALL of the cases evaluated as true for some reason, and the capture on the year didn't even work. What am I doing wrong? Testing all of my regex at regex101 worked fine, but not in the script.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I see two issues that are central to your question.

First, you apparently want to save precompiled regexes in the variables $white, $singleyear, and $nummonth, but you are not using the right operator for that - you should use qr// to compile and save the regex. Code like my $white = /^s*$/; will run the regex against $_ and store the result in $white.

Second, my $monthnumber = $param =~ /^d{1,2}/; has two issues: the =~ operator used with m// in scalar context simply returns a true/false value (that's the 1 you're seeing in the output february 1), but if you want to get the capture groups from the regex, you need to use it in list context, in this case by saying my ($monthnumber) = ... (the same issue applies to $yearnumber). Second, that regex doesn't contain any capture groups!

I don't get exactly the output you claim (although it's close) - please have a look at Minimal, Complete, and Verifiable example, especially since your post initially contained quite a few syntax errors. If I apply the fixes I described above, I get the output

march 1999

which is what I would expect - I hope you can figure out how to fix the off-by-one error.

Update: I should add that you also don't need to try and parse date/times yourself. My favorite module for date/time handling is DateTime (together with DateTime::Format::Strptime), but in this case the core Time::Piece is enough:

use Time::Piece;
my $param = "02 1999";
my $dt = Time::Piece->strptime($param, "%m %Y");
print $dt->fullmonth, " ", $dt->year, "
";       # prints "February 1999"

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...