如何使用Perl正则表达式摆脱在if
构造中使用未初始化的值?
使用下面的代码时,我会使用未初始化的值消息。
if($arrayOld[$i] =~ /-(.*)/ || $arrayOld[$i] =~ /\#(.*)/)
使用下面的代码时,我没有输出。
if(defined($arrayOld[$i]) =~ /-(.*)/ || defined($arrayOld[$i]) =~ /\#(.*)/)
检查变量是否具有给定上述代码的值的正确方法是什么?
答案 0 :(得分:2)
尝试:
if($arrayOld[$i] && $arrayOld[$i] =~ /-|\#(.*)/)
在对它运行regx之前,首先检查$ arrayOld [$ i]的值。
(还将||
合并到正则表达式中。)
答案 1 :(得分:1)
根据评论中的错误消息,您正在访问未定义的@arrayOld
元素。在没有看到其余代码的情况下,这可能表明程序中存在错误,或者只是预期的行为。
如果你理解为什么 $arrayOld[$i]
是undef
,并且你想在没有收到警告的情况下允许这样做,那么你可以做几件事。 Perl 5.10.0引入了defined-or operator //
,您可以用它来替换{{1}}的空字符串:
undef
或者,您可以关闭警告:
use 5.010;
...
if(($arrayOld[$i] // '') =~ /-(.*)/ || ($arrayOld[$i] // '') =~ /\#(.*)/)
在这里,我使用do来限制警告被禁用的时间。但是,如果if (do { no warnings 'uninitalized';
$arrayOld[$i] =~ /-(.*)/ || $arrayOld[$i] =~ /\#(.*)/ })
为$i
,则关闭警告也会抑制警告。使用undef
可以准确指定允许的//
内容,以及应该使用的确切值,而不是undef
。
注意:undef
正在defined函数的结果上运行模式匹配,这将是一个真/假值;不是你要测试的字符串。
答案 2 :(得分:1)
要以狭隘的方式回答您的问题,您可以使用
阻止该行代码中的未定义值警告if (defined $i && defined $arrayOld[$i]
&& ($arrayOld[$i] =~ /-(.*)/ || $arrayOld[$i] =~ /\#(.*)/))
{
...;
}
也就是说,评估$i
或表达式$arrayOld[$i]
可能会导致未定义的值。请注意上面写的必要括号,因为&&
和||
之间的优先级不同,前者绑定更紧密。对于问题中的特定模式,您可以通过将模式组合到一个正则表达式来回避这个优先级问题,但在一般情况下这可能很棘手。
我建议不要使用上面令人不快的代码。继续阅读,看看你的问题的优雅解决方案,Perl为你工作,更容易阅读。
从your earlier question稍微宽泛的上下文中,$i
是一个循环变量,并且肯定会定义构造,因此测试$i
是过度的。你的代码盲目地从@arrayOld
中提取元素,并且Perl很乐意。如果没有任何内容,则会得到未定义的值。
这种一对一的偷窥和戳戳在C程序中很常见,但在Perl中,几乎总是一个红旗,你可以更优雅地表达你的算法。考虑下面的完整的工作示例。
#! /usr/bin/env perl
use strict;
use warnings;
use 5.10.0; # given/when
*FILEREAD = *DATA; # for demo only
my @interesting_line = (qr/-(.*)/, qr/\#(.*)/);
$/ = ""; # paragraph mode
while(<FILEREAD>) {
chomp;
my @arrayOld = split /\n/;
my @arrayNewLines;
for (1 .. @arrayOld) {
given (shift @arrayOld) {
push @arrayNewLines, $_ when @interesting_line;
push @arrayOld, $_;
}
}
print "\@arrayOld:\n", map("$_\n", @arrayOld), "\n",
"\@arrayNewLines:\n", map("$_\n", @arrayNewLines);
}
__DATA__
#SCSI_test # put this line into @arrayNewLines
kdkdkdkdkdkdkdkd
dkdkdkdkdkdkdkdkd
- ccccccccccccccc # put this line into @arrayNewLines
该行
use 5.10.0;
启用Perl的given
/when
switch statement,这可以很好地决定哪个数组获得给定的输入行。
如评论所示
*FILEREAD = *DATA; # for demo only
用于此Stack Overflow演示。在您的真实代码中,您有open FILEREAD, ...
。将问题中的输入放入Perl的DATA
文件句柄中,可以在一个独立的单元中显示代码和输入,然后我们将FILEREAD
别名为DATA
,以便其余代码落入你没有大惊小怪。
处理的核心是
for (1 .. @arrayOld) {
given (shift @arrayOld) {
push @arrayNewLines, $_ when @interesting_line;
push @arrayOld, $_;
}
}
请注意,没有defined
个检查甚至是明确的正则表达式匹配!没有$i
或$arrayOld[$i]
!发生了什么事?
首先是@arrayOld
,其中包含当前段落中的所有行,并且希望以@arrayNewLines
中的有趣行和其他所有行@arrayOld
结束。上面的代码使用shift
从@arrayOld
开出下一行。如果该行很有趣,我们会push
到@arrayNewLines
的末尾。否则,我们会将其放回@arrayOld
。
语句修饰符when @interesting_line
与来自given
的主题执行隐式智能匹配。正如“Smart matching in detail,”中针对数组进行智能匹配时所解释的那样,Perl隐式地遍历它并在第一次匹配时停止。在这种情况下,数组@interesting_line
包含与要移动到@arrayNewLines
的行匹配的已编译正则表达式。如果当前行($_
感谢given
)与这些模式中的任何一个都不匹配,则会返回@arrayOld
。
我们完成上述过程scalar @arrayOld
次,即对当前段落中的每一行执行一次。这样,我们只处理一次所有内容,而不必担心当前数组索引所在的繁琐记账。无论@arrayOld
之后剩下的是什么,shift
s必须是我们push
回到它上面的行,这是输入中发生的顺序中不感兴趣的行。
对于问题中的输入,输出为
@arrayOld: kdkdkdkdkdkdkdkd dkdkdkdkdkdkdkdkd @arrayNewLines: #SCSI_test # put this line into @arrayNewLines - ccccccccccccccc # put this line into @arrayNewLines