尽管检查了UNDEF,但仍会警告非启用变量



我今天似乎很愚蠢,或者我有一个非常奇怪的问题。请考虑以下代码:

#!/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 ){

最新更新