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

时间:2019-08-16 09:41:01

标签: 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";
} 

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

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

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

3 个答案:

答案 0 :(得分:6)

首先,我必须先在您的代码中修复语法错误,然后才能运行它(您的)语句中缺少结尾if)。请剪切并粘贴代码,而不是重新键入代码。

如果Perl告诉您正在找到undef,那几乎可以肯定。使用Data::Dumper可以向我们显示正在发生的事情。

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";
}

这给我们以下内容:

$VAR1 = [
          undef,
          undef,
          undef,
          '-24'
        ];

是的,结果中有三个undef。我们可以找出原因吗?

好吧,这是您的匹配运算符。

/\d+(\-\d+)?\s+km/gm

正在寻找数字,其后是可选的破折号和更多数字。但是,您捕获的只是该可选部分(因为它的周围带有括号)。在前三种情况下,该可选部分不会出现。因此,前三场比赛您得到undef

让我们实际匹配您想要的内容(我认为是整个数字部分),方法是在整个内容上加上更多的括号。

/(\d+(\-\d+)?)\s+km/gm

现在我们得到以下结果:

$VAR1 = [
          '12',
          undef,
          '32',
          undef,
          '0',
          undef,
          '23-24',
          '-24'
        ];

那更好。我们获得了所有想要的比赛,以及原始比赛。因此,这是我们想要的比赛的两倍。这是因为我们现在为每个匹配项提供两组括号。我们需要第一个集合来匹配并捕获数字部分,第二个集合将“-”和“ \ d +”连接在一起。但是我们不需要第二组来捕获其内容。

如果您阅读the section on "Extended Patterns" in the perlre manual page,将会看到我们可以使用(?:...)创建不包含括号的括号。因此,让我们使用它。

/(\d+(?:\-\d+)?)\s+km/gm

这给了我们

$VAR1 = [
          '12',
          '32',
          '0',
          '23-24'
        ];

我想您想要的是什么。

更新:重新阅读您的问题,我知道您也需要“ km”。因此,我将结束括号移了过去。

/(\d+(?:\-\d+)?\s+km)/gm

这给了我们

$VAR1 = [
          '12 km',
          '32 km',
          '0 km',
          '23-24 km'
        ];

答案 1 :(得分:4)

您看到的警告是因为$_未定义。在Perl中,您可以拥有完全没有价值的变量。那是undef

在这种情况下,您要做的第一件事是检查阵列。核心Data::Dumper模块对此非常有用。或者,您可以从CPAN安装Data::Printer,我更喜欢。

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

这将输出

$VAR1 = [
          undef,
          undef,
          undef,
          '-24'
        ];

很显然,数组中有一些undef。这是因为您有一个捕获组(\-\d),它是可选的?。每次通过/g修饰符成功匹配字符串时,它将所有捕获组结果放入数组中。但是您仅有的一组是可选的,因此即使没有-\d发生,该模式也可以匹配。

您可以在Debugex上看到它。如果您想更详细地了解它,请尝试使用Regexp::Debugger模块,该模块可让您在终端中逐步调试regex。

您将必须告诉我们您实际要捕获的号码。

如果您所追求的只是破折号之后的第二个(您不必转义,则没有特殊含义),那么您不应使该捕获组为可选项。

答案 2 :(得分:-1)

两个问题。

  1. 当捕获是有条件的(例如(...)?),并且不匹配任何内容时,它将捕获undef

  2. 当捕获一个或多个捕获时,匹配项将返回捕获文本,而不是匹配的整个文本。

解决方案是删除无用且引起问题的捕获。替换

if ( my @szelmatches = $string =~ /\d+(\-\d+)?\s+km/g )

使用

if ( my @szelmatches = $string =~ /\d+(?:\-\d+)?\s+km/g )