为什么 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/, /
匹配一样。
我只是挣扎了很长时间才想出一个像这样的可工作的小 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/, /
匹配一样。