要狭隘地回答您的问题,您可以在该行代码中防止未定义值警告
if (defined $i && defined $arrayOld[$i]
&& ($arrayOld[$i] =~ /-(.*)/ || $arrayOld[$i] =~ /\#(.*)/))
{
...;
}
也就是说,计算其中一个$i
或表达式$arrayOld[$i]
可能会导致未定义的值。注意上面写的额外的括号层,因为 和 之间的优先级不同&&
,||
前者绑定更紧密。对于您问题中的特定模式,您可以通过将您的模式组合成一个正则表达式来回避这个优先级问题,但在一般情况下这可能会很棘手。
我建议不要使用上面令人不快的代码。继续阅读以查看一个优雅的问题解决方案,它让 Perl 为您完成工作并且更容易阅读。
回头看
从您之前的问题的更广泛的背景来看,$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 语句,这是一种很好的方式来决定哪个数组获得给定的输入行。
正如评论所示
*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
. @arrayOld
上面的代码从with中取出下一行shift
。如果该行很有趣,我们push
将它放到@arrayNewLines
. 否则,我们将其放回@arrayOld
.
语句修饰符when @interesting_line
与来自 的主题执行隐式智能匹配given
。正如“详细智能匹配”中所解释的,当对数组进行智能匹配时,Perl 会隐式循环它并在第一次匹配时停止。在这种情况下,数组@interesting_line
包含已编译的正则表达式,这些正则表达式匹配您要移动到的行@arrayNewLines
。如果当前行($_
感谢given
)与这些模式中的任何一个都不匹配,则返回@arrayOld
.
我们将前面的过程精确地执行scalar @arrayOld
多次,即当前段落中的每一行执行一次。这样,我们只处理一次所有内容,而不必担心当前数组索引在哪里的繁琐记账。@arrayOld
在这么多 s 之后剩下的任何东西都shift
必须是我们push
重新编入它的行,这些行是按输入中出现的顺序排列的无趣的行。
样本输出
对于您问题中的输入,输出是
@arrayOld:
kdkdkdkdkdkdkdkd
dkdkdkdkdkdkdkdkdkd
@arrayNewLines:
#SCSI_test # 将此行放入@arrayNewLines
- ccccccccccccccc # 将此行放入@arrayNewLines