我在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告诉我一切都很好。
我知道您可以将它写得更简单/更简短/更好/更快/更精细,但是老实说我认为这应该可行。你们知道我在做什么错吗?
答案 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)
两个问题。
当捕获是有条件的(例如(...)?
),并且不匹配任何内容时,它将捕获undef
。
当捕获一个或多个捕获时,匹配项将返回捕获文本,而不是匹配的整个文本。
解决方案是删除无用且引起问题的捕获。替换
if ( my @szelmatches = $string =~ /\d+(\-\d+)?\s+km/g )
使用
if ( my @szelmatches = $string =~ /\d+(?:\-\d+)?\s+km/g )