在Perl中,替换文本中的反向引用后跟数字字面量

12

我在替换文本中使用了反向引用,但在它后面还有一个字面量,出现了问题。我已经尝试了以下内容:

perl -0pi -e "s/(<tag1>foo<\/tag1>\n\s*<tag2>)[^\n]*(<\/tag2>)/\1${varWithLeadingNumber}\2/" file.xml
perl -0pi -e "s/(<tag1>foo<\/tag1>\n\s*<tag2>)[^\n]*(<\/tag2>)/\g{1}${varWithLeadingNumber}\g{2}/" file.xml

第一个方法会出现问题,因为${varWithLeadingNumber}以数字开头,但是我认为我上面第二种尝试中的\g{1}结构应该可以解决这个问题。我使用的是perl 5.12.4版本。


4
你确定问题不是出在命令行解释器上吗?我建议使用单引号包裹脚本(除了收集命令行解释器变量的部分),这样可以减少需要转义的反斜杠数量。 - Jonathan Leffler
我刚刚尝试了一下,例如 perl -0pi -e 's/(<tag1>foo<\/tag1>\n\s*<tag2>)[^\n]*(<\/tag2>)/\g{1}25\g{2}/' file.xml,结果是一样的。替换文本最终变成了 g{1}25g{2} - jonderry
1个回答

21

在替换表达式中使用 \1\2 等是错误的。 \1 是一个正则表达式模式,意思是“匹配第一个捕获组所匹配的内容”,这在替换表达式中没有意义。正则表达式模式不应该在正则表达式之外使用!你应该使用 $1$2 等。

修复了 \1 后,你应该这样写:

perl ... -e'... s/.../...$1$varWithLeadingNumber.../ ...'

话虽如此,我认为varWithLeadingNumber应该是一个shell变量?如果它是Perl变量,您不应该有任何问题。如果您让shell插值varWithLeadingNumber,可以使用以下方法解决问题:

perl ... -e"... s/.../...\${1}${varWithLeadingNumber}.../ ..."

请注意,如果$varWithLeadingNumber包含"$","@","\"或"/",则您将遇到问题,因此您可能希望使用命令行参数而不是插值。

perl ... -pe'
   BEGIN { $val = shift; }
   ... s/.../...$1$val.../ ...
' "${varWithLeadingNumber}"

您还可以使用环境变量。

export varWithLeadingNumber
perl ... -pe's/.../...$1$ENV{varWithLeadingNumber}.../'
或者
varWithLeadingNumber=varWithLeadingNumber \
    perl ... -pe's/.../...$1$ENV{varWithLeadingNumber}.../'
如果你确实有一个\1
s/...\1.../.../

你可以通过多种方式避免这个问题,包括:

s/...(?:\1).../.../

如果我执行 perl -0pi -e 's/(<tag1>foo<\/tag1>\n\s*<tag2>)[^\n]*(<\/tag2>)/${1}'${varWithLeadingNumber}'${2}/' file.xml,这个命令就能正常工作。谢谢。 - jonderry
仅适用于 $varWithLeadingNumber 带有数字开头的有限值。我建议不要这样做。 - ikegami

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接