为什么在这种情况下perl不能保持match变量不变?

时间:2019-07-16 11:48:53

标签: regex perl regex-group

我只是想了很长时间才想出一个像这样的可工作的小perl内胆:

perl -pe 'if (/^(".*",").*, /) { $a = $1; 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$1/g}

但是没有。变量$1从来都是空的。鉴于perl docs I read对持久性的评价,这令我感到惊讶:

  

这些匹配变量通常会保留到下一次成功的模式匹配为止。

只有当我开始将结果存储在自己的变量中时,我才能从替换表达式中访问结果:

if (/^(".*",").*, /) { $a = $1; s/, /"\n$a/g}

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

2 个答案:

答案 0 :(得分:4)

匹配变量的值的确存在,直到下一次成功的模式匹配(或直到退出匹配发生的范围)为止。

在您的情况下,它们发生了变化,因为模式匹配成功。您已成功匹配模式, 。因此,捕获变量将反映该匹配的捕获所捕获的文本。 $1返回与不存在的第一个捕获匹配的文本,因此它返回了undef

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

答案 1 :(得分:3)

您问:

  

为什么在我的搜索和替换操作中,不仅没有成功匹配,而且根本没有匹配请求,为什么要清除$ 1?

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

要让s/PATTERN/REPLACEMENT/做任何事,PATTERN必须 match 。因此,如果s///操作的结果根本没有替代,您就知道它的PATTERN正则表达式匹配成功。然后评估更换。

(在您的情况下,s/, /.../模式在第二行中的文本bar a之后至少在逗号和空格处匹配一次。)

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