Reputation: 135
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";
Upvotes: 3
Views: 506
Reputation: 385635
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 );
Upvotes: 8
Reputation: 66873
That $1
in the replacement string is just successive chars $
and 1
, and to make it into a variable for the first capture you'd have to go through bad hoops.†
How about an alternative
my string = q(a pet dog);
my $pattern = qr/a pet (\w+)/;
my $new = $string =~ s/$pattern/ repl($1) /er;
sub repl {
my ($capture) = @_;
return "$capture is a good boy";
}
where the sub is really just
sub repl { "$_[0] is a good boy" }
It's a little more but then it's more capable and flexible.
† Or, as it turns out per ikegami's answer, use String::Substitution which wraps up into a single call all needed 'niceties' so to avoid doing bad things (string eval
that is)
Upvotes: 4