Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In perl, backreference in replacement text followed by numerical literal

Tags:

regex

perl

I'm having trouble with a backreference in my replacement text that is followed by a literal. I have tried the following:

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

The first of course causes problems because ${varWithLeadingNumber} begins with a number, but I thought the \g{1} construct in my second attempt above was supposed to solve this problem. I'm using perl 5.12.4.

like image 386
jonderry Avatar asked Sep 26 '11 18:09

jonderry


1 Answers

Using \1, \2, etc in the replacement expression is wrong. \1 is a regular expression pattern that means "match what the first capture matched" which makes no sense in a replacement expression. Regular expression patterns should not be used outside of regular expressions! $1, $2, etc is what you should be using there.

After fixing \1, you have

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

That said, I think varWithLeadingNumber is supposed to be a shell variable? You shouldn't have any problems if it's a Perl variable. If you're having the shell interpolate varWithLeadingNumber, the problem can be fixed using

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

Note that you will have problems if $varWithLeadingNumber contains "$", "@", "\" or "/", so you might want to use a command line argument instead of interpolation.

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

You could also use an environment variable.

export varWithLeadingNumber
perl ... -pe's/.../...$1$ENV{varWithLeadingNumber}.../'

or

varWithLeadingNumber=varWithLeadingNumber \
    perl ... -pe's/.../...$1$ENV{varWithLeadingNumber}.../'

If you did have a \1

s/...\1.../.../

you can avoid the problem a number of ways including

s/...(?:\1).../.../
like image 52
ikegami Avatar answered Nov 15 '22 19:11

ikegami