为什么 perl 在这种情况下不保留匹配变量?

Why does perl not keep the match variable around in this situation?

我只是挣扎了很长时间才想出一个像这样的可工作的小 perl 单行代码:

perl -pe 'if (/^(".*",").*, /) { $a = ; s/, /"\n$a/g}'

我的输入数据是这样的:

"foo","bar a"
"baz","bar a, bar b, bar c"

我正在将其转换为:

"foo","bar a"
"baz","bar a"
"baz","bar b"
"baz","bar c"

基本上我只想匹配某些行 (if (/, /)...) 并在这些行上用原始行的一部分替换该匹配项的所有实例。带有匹配组的 s///g 将不起作用,因为它不会正确递归,必须在替换开始之前找出替换字符串。

if (/^(".*",").*, /) { s/, /"\n/g}

然而并没有。 var </code> 从来都是空的。鉴于 perl <a href="https://docstore.mik.ua/orelly/perl3/lperl/ch09_05.htm" rel="nofollow noreferrer">docs I read</a> 所说的持久性,这让我感到惊讶:</p> <blockquote> <p>These match variables generally stay around until the next successful pattern match.</p> </blockquote> <p>只有当我开始将结果存储在我自己的变量中时,我才能从替换表达式中访问结果:</p> <pre><code>if (/^(".*",").*, /) { $a = ; s/, /"\n$a/g}

为什么 在我的搜索和替换中不仅没有 成功 匹配,而且根本没有匹配请求时被清除?是否有更好的方法来解决这个问题?

匹配变量的值确实会一直保留到下一次成功的模式匹配(或直到退出发生匹配的范围)。

在您的例子中,它们发生了变化,因为模式匹配成功。您已成功匹配模式 , 。因此,捕获变量将反映该匹配项的捕获所捕获的文本。 </code> returns non-existent 第一次捕获匹配的文本,因此返回 <code>undef.

$ perl -e'
   $_ = "a";
   s/(a)/a/;  CORE::say  // "[undef]";  # Successful match
   s/(c)/c/;  CORE::say  // "[undef]";  # Unsuccessful match
   s/a/a/;    CORE::say  // "[undef]";  # Successful match
'
a
a
undef

你问:

Why was being cleared when not only was there no successful match, there was no request for a match at all in my search and replace?

您是否可能将 匹配 捕获 混为一谈?

为了 s/PATTERN/REPLACEMENT/ 执行任何操作,PATTERN 必须 匹配 。因此,如果 s/// 操作导致任何替换,您就知道它的 PATTERN regex-matched 成功了。然后评估 REPLACEMENT。

(在您的情况下,s/, /.../ PATTERN 在第二个输入行的文本 bar a 之后的逗号和 space 上至少匹配一次。)

当然,当发生这种情况时,解释器会将所有捕获元素(</code>、<code> 等)重置为捕获的任何 PATTERN。同样,这是在评估 REPLACEMENT 之前。由于您的 PATTERN 没有捕获任何内容,因此这些元素是未定义的,就像您明确地进行了 non-capturing m/, / 匹配一样。