列表中正则表达式的奇怪行为匹配

时间:2017-05-01 20:47:03

标签: perl

我经历了使用正则表达式捕获来分配列表元素的奇怪行为 - 这让我很困惑,而且我在文档和其他地方的任何地方都找不到解释。我使用的代码是这样的:

$_ = "one 1 two 2 three 3";
my $n = 1;
my @tt = (
    /one (\S+)/ ? (one => $1) : (),
    /two (\S+)/ ? (two => $1) : (),
    /three (\S+)/ ? (three => $1) : (),
);
print "Array: " . join(" ", @tt) . "\n";

出人意料地打印出来:

Array: one 3 two 3 three 3

虽然我希望它会打印出来:

Array: one 1 two 2 three 3

因此,当我在列表赋值中使用//?:时,我总是从最后一个(!)匹配表达式获取捕获 - 无论是$1还是$&或其他任何涉及捕获的内容。

当我用?:围绕每个do {}时,一切都按预期工作。

我的问题是 - 我做错了什么?这是一个我不知道的错误或一些众所周知(或隐藏)的功能/行为吗?

谢谢!

PS:如果这很重要 - 我在Ubuntu 16.04.2上使用标准的perl 5.22.1,尽管Perl 5.8.8和5.24.1上的行为是相同的

编辑:虽然这种行为的原因与此问题相同 -  compilation order and post prefix opertors - 但上下文完全不同,问题是相似的并不是很明显,因为前面的问题是关于将参数传递给子,而在我的问题中没有涉及潜艇。

1 个答案:

答案 0 :(得分:4)

compilation order and post prefix opertors的答案也回答了你的问题。以下是摘要。

一般来说,避免在表达式 [1] 中设置和读取变量的情况。

您的代码执行以下操作:

  1. 您设置$1
  2. 您在堆栈上放置一个字符串$1。 (不是$1的副本!)
  3. 您设置$1
  4. 您在字符串上放置一个字符串$1
  5. 您设置$1
  6. 您在字符串上放置一个字符串$1
  7. 您将堆栈的内容(字符串,$1,字符串,$1,字符串,$1)复制到@tt。此时$13
  8. 您可以使用"$1"代替$1解决此问题,因为"$1"会从$1构建新字符串。

    1. 那就是说,my $x = /(foo|bar)/ ? $1 : 'default';不会给你任何问题。
相关问题