【问题标题】:Perl: Capturing variable cannot be set undef?Perl:捕获变量不能设置为undef?
【发布时间】:2022-01-20 10:55:27
【问题描述】:

我有几个捕获的正则表达式,显然捕获变量保留了最后一次有效捕获的值:

# Two scalars to use for regexp
$x = 'abc'; 
$y = 'def'; 

# first regexp
$x =~ /^(ab)/; 
$x = $1; 

# second regexp
$y =~ /^(de)/; 
$y = $1; 
print \"$x\n$y\";

输出是:

ab
de

这里是单行版本:

perl -e "$x='abc'; $y='def'; $x =~ /^(ab)/; $x=$1; $y =~ /^(de)/; $y=$1; print \"$x\n$y\";"

如果$y='def'改成$y='zdef'

perl -e "$x='abc'; $y='zdef'; $x =~ /^(ab)/; $x=$1; $y =~ /^(de)/; $y=$1; print \"$x\n$y\";"

输出是:

ab
ab

如果我想在$x=$1 之后设置$1=undef 以删除$1 中的当前值

perl -e "$x='abc'; $y='zdef'; $x =~ /^(ab)/; $x=$1; $1=undef; $y =~ /^(de)/; $y=$1; print \"$x\n$y\";"

输出是:

Modification of a read-only value attempted at -e line 1.

显然,捕获变量是无法更改的。

我想知道如何解决这个问题。我想要的结果是:

ab
..

其中.. 表示“空”。就像在这种情况下,第一个正则表达式是 undef ($x='zabc):

perl -e "$x='zabc'; $y='def'; $x =~ /^(ab)/; $x=$1; $y =~ /^(de)/; $y=$1; print \"$x\n$y\";"

..
de

【问题讨论】:

标签: regex perl capturing-group


【解决方案1】:

您需要谨慎使用捕获变量$1(和$2$3 等)。它们在成功的模式匹配时分配(并且未分配),因此您必须确保您有正确的匹配。通常,您会这样做:

if ('abc' =~ /^(ab)/) {
    $x = $1;
}
if ('zdef' =~ /^(de)/) {
    $y = $1;
}

这样,您永远不会得到错误的赋值。

但是,还有其他方法可以做到这一点。模式匹配本身会给出一个返回值,这取决于上下文。

$n   = 'abc' =~ /^(ab)/;        # $n = 1 for "true". This is scalar context
($n) = 'abc' =~ /^(ab)/;        # $n = 'ab', the captured string. This is list context
$n = () = 'abc' =~ /(.)/g;      # $n = 3, for 3 matches. /g gives multiple matches
($f, $g) = 'abc' =~ /(.)/g;     # $f = 'a', $g = 'b'. List context

【讨论】:

    【解决方案2】:

    perl 正则表达式使用全局变量是很常见的。 如果没有捕获,$1 将是最后一个成功捕获的组。

    正如我所说,它很常见,并且是 perl 的工作方式。

    你能做什么? 首先,获取所有捕获的组,如下所示:

    @captures = $y =~ /^(de)/;
    

    然后使用它。

    第二,使用 ternar 语句:

    $y = $y =~ /(ho)/ ? $1 : undef;
    

    或者你可以考虑这个包https://metacpan.org/pod/Regex::Object 它有助于处理这类事情。但是您需要一些关于 CPAN 和对象的基本知识。

    【讨论】:

    • Ternar 语句在我看来是最优雅的处理方式。
    【解决方案3】:

    替换

    $x =~ /^(ab)/; 
    $x = $1; 
    

    ( $x ) = $x =~ /^(ab)/;
    

    $x = $x =~ /^(ab)/ ? $1 : undef;
    

    前者依赖于这样一个事实,即匹配运算符返回它在列表上下文中调用时捕获的序列。

    后者依赖于匹配操作符在标量上下文中调用时返回匹配是否成功这一事实。

    【讨论】:

    • 注意在帖子中添加解释,因为它已被接受,即使它没有对之前的其他答案添加任何内容?
    • @Mustafa Aydın,看起来有点多余,但已经完成了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2012-11-18
    • 2019-12-13
    • 1970-01-01
    相关资源
    最近更新 更多