尽管检查了undef,但是关于uninitailized变量的警告

Bin*_*rus 4 regex perl initialization regex-group

我今天好像很傻,或者我有一个非常奇怪的问题.请考虑以下代码:

#!/usr/bin/perl

use strict;
use warnings;
use warnings::unused;
use warnings FATAL => 'uninitialized';

my ($String, $Pattern);

$Pattern = "pattern";
$String = "pattern\n";

if (($String =~ m/^([^\ ]+).*$/s) &&
    defined($1) &&
    ($1 =~ m/^.*$Pattern$/s)) {

  print $1."\n";
}
Run Code Online (Sandbox Code Playgroud)

此代码生成以下警告(然后因为而停止use warnings FATAL => 'uninitialized';):

Use of uninitialized value $1 in concatenation (.) or string at [...]
Run Code Online (Sandbox Code Playgroud)

我真的不明白这个,因为我正在测试是否$1在使用之前定义(初始化).罪魁祸首似乎是最后的条件线(即($1 =~ m/^.*$Pattern$/s)).如果我把它留下,警告就会消失.

但为什么?根据我的理解,该行应该只测试 $1,但不能更改其值($Pattern并且该RegEx的其余部分不包含括号,因此$1不应重新分配可能的匹配).

嗯......一边想着它,它在我脑海中是Perl可能设置$1及其同事情况下,当一个正则表达式是匹配,是否有在正则表达式的括号内.这可以解释这种行为.这是真的吗?

yst*_*sth 9

perldoc perlvar:

包含来自上一次成功模式匹配的相应捕获括号集的子模式,不包括已经退出的嵌套块中匹配的模式.

由于第二个匹配是最后一次成功的模式匹配,因此if块内部$1是undef.

你可以这样做:

my ($match) = ($String =~ m/^([^\ ]+).*$/s);
if (defined $match && $match =~ m/^.*$Pattern$/s) {
    print $match."\n";
}
Run Code Online (Sandbox Code Playgroud)


tin*_*ita 8

我在上面的评论中创建了一个答案:

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
) {
Run Code Online (Sandbox Code Playgroud)

因此,每当正则表达式匹配时,它将重置所有数字变量(以及其他正则表达式相关变量).

我看到的唯一解决方案是将条件分开并保存$1在一个额外的变量中.无论如何,这通常是一件好事.

if ($String =~ m/^([^\ ]+).*$/s and defined $1) {
    my $match = $1;
    if ($match =~ m/^.*$Pattern$/s) { ... }
}
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,您甚至不必检查,defined $1因为如果此模式匹配,$1将始终定义.这取决于模式.

perldoc perlvar:

$<digits> ($1, $2, ...)
        Contains the subpattern from the corresponding set of capturing
        parentheses from the last successful pattern match [...]
Run Code Online (Sandbox Code Playgroud)