我今天似乎很愚蠢,或者我有一个非常奇怪的问题。请考虑以下代码:
#!/usr/bin/perl
use strict;
use warnings;
use warnings::unused;
use warnings FATAL => 'uninitialized';
my ($String, $Pattern);
$Pattern = "pattern";
$String = "patternn";
if (($String =~ m/^([^ ]+).*$/s) &&
defined($1) &&
($1 =~ m/^.*$Pattern$/s)) {
print $1."n";
}
此代码会产生以下警告(然后由于use warnings FATAL => 'uninitialized';
而停止):
Use of uninitialized value $1 in concatenation (.) or string at [...]
我真的不明白这一点,因为我在使用之前正在测试$1
是否定义(初始化)。罪魁祸首似乎是最后一个条件线(即($1 =~ m/^.*$Pattern$/s)
)。如果我离开了,警告就消失了。
但是为什么?根据我的理解,该行应仅 test $1
,但不要更改其值($Pattern
和该正则其其余的不包含括号的内容,因此不应将$1
重新分配给可能的匹配)。
hmmm ...在思考时,我想到的是,perl可能会在情况下将$1
及其同事设置为匹配时的每个情况,无论是在言论中是否有括号。这将解释行为。是真的吗?
perldoc perlvar:
包含来自上一个成功模式匹配的相应捕获括号集的子图案,而不是在已经退出的嵌套块中匹配的模式。
由于第二个匹配是最后一个成功的模式匹配,因此在if block $1
是undef。
您可以做:
my ($match) = ($String =~ m/^([^ ]+).*$/s);
if (defined $match && $match =~ m/^.*$Pattern$/s) {
print $match."n";
}
我正在从上面的评论中创建答案:
if (($String =~ m/^([^ ]+).*$/s) && # If matching, this will set $1
defined($1) && # Here $1 is still defined
($1 =~ m/^.*$Pattern$/s) # If matching, will reset all $1, .. vars
) {
因此,每当正则匹配时,它将重置所有数字变量(和其他Regex相关变量)。
我看到的唯一解决方案是将条件分开,并将$1
保存在额外的变量中。无论如何,这通常是一件好事。
if ($String =~ m/^([^ ]+).*$/s and defined $1) {
my $match = $1;
if ($match =~ m/^.*$Pattern$/s) { ... }
}
请注意,在这种情况下,您甚至不必检查defined $1
,因为如果此模式匹配,$1
将始终定义。这取决于模式。
perldoc perlvar:
$<digits> ($1, $2, ...)
Contains the subpattern from the corresponding set of capturing
parentheses from the last successful pattern match [...]
如果您不知道复杂的语句在做什么,请将其分为部分。
if( $String =~ m/^([^ ]+).*$/s ){
if( defined($1) ){
if( $1 =~ m/^.*$Pattern$/s ){