奇数“使用未初始化的值”,正则表达式错误

gam*_*1t9 2 perl

我正在Windows 10上使用Strawberry Perl5。看来我的正则表达式已损坏,或者regex101不会告诉我真相。我想赶上'num km'。即使我的数组似乎是正确的长度,也经常会说“使用未初始化的值”。

my $string = "^?~ --_ 12 km aéeklwa   32 km |  \|Ä?^ 0 km  23-24 km";

if (@szelmatches = $string =~ /\d+(\-\d+)?\s+km/gm) {
    my $number_of_elements = scalar(@szelmatches);
    print "Elements in the array : $number_of_elements  \n";
}

foreach (@szelmatches) {
    print "$_\n";
} 

Run Code Online (Sandbox Code Playgroud)

输出: 数组中的元素:4
在C:\ misc \ perlek \ wttr \ szel.pl第16行的串联(。)或字符串中使用未初始化的值$ _。

我已经运行define()检查,但似乎我的数组元素都已定义。将\-更改为。{1}有时是可行的,但是这样写很烦人。regex101.com和regexr.com告诉我一切都很好。

我知道您可以将它写得更简单/更短/更好/更快/更精细,但老实说,这应该可行。你们知道我在做什么错吗?

Dav*_*oss 6

Firstly, I had to fix a syntax error in your code before I could run it (the closing ) was missing from your if statement). Please cut and paste code, rather than retyping it.

If Perl tells you that it's finding undefs then it's almost certainly right. Using Data::Dumper can show us what is going on.

use warnings;
use Data::Dumper;

my $string = "^?~ --_ 12 km aéeklwa   32 km |  \|Ä?^ 0 km  23-24 km";

if (@szelmatches = $string =~ /\d+(\-\d+)?\s+km/gm) {
    my $number_of_elements = scalar(@szelmatches);
    print "Elements in the array : $number_of_elements  \n";
}

print Dumper \@szelmatches;

foreach (@szelmatches) {
    print "$_\n";
}
Run Code Online (Sandbox Code Playgroud)

That gives us the following:

$VAR1 = [
          undef,
          undef,
          undef,
          '-24'
        ];
Run Code Online (Sandbox Code Playgroud)

So, yes, there are three undefs in your results. Can we work out why?

Well, here's your match operator.

/\d+(\-\d+)?\s+km/gm
Run Code Online (Sandbox Code Playgroud)

It's looking for digits followed by an optional dash and more digits. But it's only that optional part that you're capturing (as it has parentheses around it). And in the first three cases, that optional section doesn't appear. So you get undef for those first three matches.

Let's actually match what you want (the whole digits section, I think) by putting more parentheses around the whole thing.

/(\d+(\-\d+)?)\s+km/gm
Run Code Online (Sandbox Code Playgroud)

Now we get this result:

$VAR1 = [
          '12',
          undef,
          '32',
          undef,
          '0',
          undef,
          '23-24',
          '-24'
        ];
Run Code Online (Sandbox Code Playgroud)

That's better. We get all of the matches we want, alongside the original ones. So, that's twice as many matches as we want. That's because we now have two sets of parentheses for each match. We need the first set to match and capture the digit section and the second set to join together the "-" and the "\d+". But we don't need the second set to capture its contents.

If you read the section on "Extended Patterns" in the perlre manual page, you'll see that we can create non-capturing parentheses with (?:...). So let's use that.

/(\d+(?:\-\d+)?)\s+km/gm
Run Code Online (Sandbox Code Playgroud)

And that gives us:

$VAR1 = [
          '12',
          '32',
          '0',
          '23-24'
        ];
Run Code Online (Sandbox Code Playgroud)

Which is, I think, what you wanted.

Update: Re-reading your question, I realise that you wanted the 'km' as well. So I've moved the closing parentheses past that.

/(\d+(?:\-\d+)?\s+km)/gm
Run Code Online (Sandbox Code Playgroud)

And that gives us:

$VAR1 = [
          '12 km',
          '32 km',
          '0 km',
          '23-24 km'
        ];
Run Code Online (Sandbox Code Playgroud)