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

Perl “奇数”;未初始化值的使用“;,正则表达式错误,perl,Perl,我在Windows10上使用的是草莓Perl5。看起来我的正则表达式坏了,或者regex101不会告诉我真相。我想接“num km”。即使我的数组似乎是正确的长度,它也经常说“使用未初始化值” my$string=“^ˇ~--”12公里aéeklwa 32公里\| 0公里23-24公里”; 如果(@szelmatches=$string=~/\d+(\-\d+)?\s+km/gm){ 我的$number_of_元素=标量(@szelmatches); 打印“数组中的元素:$number\u of

我在Windows10上使用的是草莓Perl5。看起来我的正则表达式坏了,或者regex101不会告诉我真相。我想接“num km”。即使我的数组似乎是正确的长度,它也经常说“使用未初始化值”

my$string=“^ˇ~--”12公里aéeklwa 32公里\| 0公里23-24公里”;
如果(@szelmatches=$string=~/\d+(\-\d+)?\s+km/gm){
我的$number_of_元素=标量(@szelmatches);
打印“数组中的元素:$number\u of\u Elements\n”;
}
foreach(@szelmatches){
打印“$\u\n”;
} 
输出: 数组中的元素:4
在C:\misc\perlek\wttr\szel.pl第16行的串联(.)或字符串中使用未初始化的值$uu

我已经运行了defined()检查,但似乎我的数组元素都已定义。有时改为{1}会奏效,但这样写很烦人。regex101.com和regexr.com告诉我一切正常


我知道你可以写得更简单/更短/更好/更快/更好等等,但我真的认为这应该行得通。你们知道我做错了什么吗

您看到的警告是因为
$\uu
未定义。在Perl中,可以使用没有任何值的变量。这是
undef

在这种情况下,您要做的第一件事是检查阵列。核心模块就是这样的。或者你可以从CPAN安装,我更喜欢

print Dumper \@szelmatches;
foreach (@szelmatches) {
    print "$_\n";
}
这将输出

$VAR1 = [
          undef,
          undef,
          undef,
          '-24'
        ];
显然,数组中有一些
undef
s。这是因为您有一个捕获组
(\-\d)
,它是可选的
。每次通过
/g
修饰符成功匹配字符串时,它都会将所有捕获组结果放入数组中。但是您仅有的组是可选的,因此即使没有
-\d
进行操作,模式也会匹配

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";
}
你可以在屏幕上看到这一点。如果您想更详细地使用它,请尝试该模块,它将允许您在终端中逐步调试正则表达式

您必须告诉我们您实际想要捕获的数字


如果您所追求的是破折号后的第二个破折号(您不必转义,它没有特殊意义),那么您不应该将该捕获组设置为可选的。

首先,我必须在运行代码之前修复代码中的语法错误(结束
If
语句中丢失了
)。请剪切并粘贴代码,而不是重新键入

如果Perl告诉您它正在查找
undef
s,那么几乎可以肯定它是正确的。使用可以告诉我们发生了什么

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'
        ];
因此,是的,结果中有三个
unde
s。我们能找出原因吗

好的,这是你的接线员

/\d+(\-\d+)?\s+km/gm
它正在寻找后面跟一个可选破折号和更多数字的数字。但它只是您要捕获的可选部分(因为它周围有括号)。在前三种情况下,可选部分不会出现。因此,对于前三个匹配项,您将获得
unde

让我们通过在整件事周围加上更多的括号来匹配您想要的内容(我认为是整个数字部分)

/(\d+(\-\d+)?)\s+km/gm
现在我们得到这个结果:

$VAR1 = [
          '12',
          undef,
          '32',
          undef,
          '0',
          undef,
          '23-24',
          '-24'
        ];
那更好。我们得到了所有我们想要的比赛,除了最初的比赛。所以,这是我们想要的两倍。这是因为我们现在每个匹配有两组括号。我们需要第一组匹配并捕获数字部分,第二组连接“-”和“\d+”。但是我们不需要第二组来捕获它的内容

如果您阅读,您将看到我们可以使用
(?:…)
创建非捕获括号。让我们用这个

/(\d+(?:\-\d+)?)\s+km/gm
/(\d+(?:\-\d+)?\s+km)/gm
这给了我们:

$VAR1 = [
          '12',
          '32',
          '0',
          '23-24'
        ];
$VAR1 = [
          '12 km',
          '32 km',
          '0 km',
          '23-24 km'
        ];
我想这就是你想要的

更新:重新阅读您的问题,我意识到您也想要“km”。我把右括号移过去了

这给了我们:

$VAR1 = [
          '12',
          '32',
          '0',
          '23-24'
        ];
$VAR1 = [
          '12 km',
          '32 km',
          '0 km',
          '23-24 km'
        ];
两个问题

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

  • 当有一个或多个捕获时,匹配将返回捕获文本,而不是匹配的整个文本

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

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


    欢迎来到堆栈溢出。代码中有一些语法错误。请回答您的问题并解决它们,以便我们能够提供帮助。谢谢。始终使用
    严格使用;使用警告
    /m
    在没有
    ^
    $
    @DaveCross的模式中是无用的。我更喜欢你的答案。我也想一步一步地做这件事,但是我花了太多时间试图找到一个可以将调试器输出转换为gif的东西。谢谢,它解决了我的问题,但我有几个问题。首先,当你说“这只是你正在捕获的可选部分(因为它周围有括号)”,为什么会发生这种情况?我的意思是,我理解这个概念中的组的概念(不是真的,但让我们假装一下),但什么时候我需要组的值而不是整个匹配的值变得明显了?是否只在可选部分之后?我不能遵循这个逻辑。@gamb1t9:我认为您缺少的是,当您想在(例如)数组中存储正则表达式匹配的位时,所存储的位就是正则表达式中通过括号“捕获”的部分。我想你会发现阅读(特别是上一节)很有用。好吧,现在,我的答案很好:()不仅有利于分组,而且它还创建了一个“捕获组”,可以通过(?:来转义函数,所以它的行为就像我想象的那样。我将继续使用它,因为\d+(?:-\d+)\s+km(只有简单的?:添加到我的模式中,取消了捕获组,我想)正是我所期望的工作