regexperl

Perl: Use backreferences in a replacement string variable


I am performing a string substitution in Perl, but I have both the pattern and the replacement strings stored as scalar variables outside the regular expression operators. The problem is that I want the replacement string to be able to use backreferences.

I hope the code below will illustrate the matter more clearly.

my $pattern = 'I have a pet (\w+).';
my $replacement = 'My pet $1 is a good boy.';
my $original_string = 'I have a pet dog.';

# Not Working
my $new_string = $original_string =~ s/$pattern/$replacement/r;

# Working
#my $new_string = $original_string =~ s/$pattern/My pet $1 is a good boy./r;

# Expected: "My pet dog is a good boy."
# Actual: "My pet $1 is a good boy."
print "$new_string\n";

Solution

  • Use one the following subs from String::Substitution:

    Instead of Use this
    s/// sub_modify
    s///g gsub_modify
    s///r sub_copy
    s///gr gsub_copy

    Explanation follows.


    s/$pattern/My pet $1 is a good boy./
    

    is short for

    s/$pattern/ "My pet $1 is a good boy." /e
    

    The replacement expression ("My pet $1 is a good boy.") is a string literal that interpolates $1.

    This means that

    s/$pattern/$replacement/
    

    is short for

    s/$pattern/ "$replacement" /e
    

    The replacement expression ("$replacement") is a string literal that interpolates $replacement (not $1).


    While it may be hindering you that interpolation isn't recursive, it's a good thing that Perl isn't in the habit of executing the contents of variables as Perl code. :)

    You can use sub_copy from String::Substitution instead of s///r to solve your problem.

    use String::Subtitution qw( sub_copy );
    
    my $pattern         = 'I have a pet (\w+)\.';
    my $replacement     = 'My pet $1 is a good boy.';
    my $original_string = 'I have a pet dog.';
    
    my $new_string = sub_copy( $original_string, $pattern, $replacement );