我只是想了很长时间才想出一个像这样的可工作的小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
被清除了?并且会有更好的方法来解决这个问题吗?
答案 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/, /
匹配时一样。