How do I perform a Perl substitution on a string while keeping the original?
In Perl, what is a good way to perform a replacement on a string using a regular expression and store the value in a different variable, without changing the original?
I usually just copy the string to a new variable then bind it to the s///
regex that does the replacement on the new string, but I was wondering if there is a better way to do this?
$newstring = $oldstring;
$newstring =~ s/foo/bar/g;
Solution 1:
This is the idiom I've always used to get a modified copy of a string without changing the original:
(my $newstring = $oldstring) =~ s/foo/bar/g;
In perl 5.14.0 or later, you can use the new /r
non-destructive substitution modifier:
my $newstring = $oldstring =~ s/foo/bar/gr;
NOTE:
The above solutions work without g
too. They also work with any other modifiers.
SEE ALSO:perldoc perlrequick
: Perl regular expressions quick start
Solution 2:
The statement:
(my $newstring = $oldstring) =~ s/foo/bar/g;
Which is equivalent to:
my $newstring = $oldstring;
$newstring =~ s/foo/bar/g;
Alternatively, as of Perl 5.13.2 you can use /r
to do a non destructive substitution:
use 5.013;
#...
my $newstring = $oldstring =~ s/foo/bar/gr;
Solution 3:
Under use strict
, say:
(my $new = $original) =~ s/foo/bar/;
instead.
Solution 4:
The one-liner solution is more useful as a shibboleth than good code; good Perl coders will know it and understand it, but it's much less transparent and readable than the two-line copy-and-modify couplet you're starting with.
In other words, a good way to do this is the way you're already doing it. Unnecessary concision at the cost of readability isn't a win.
Solution 5:
Another pre-5.14 solution: http://www.perlmonks.org/?node_id=346719 (see japhy's post)
As his approach uses map
, it also works well for arrays, but requires cascading map
to produce a temporary array (otherwise the original would be modified):
my @orig = ('this', 'this sucks', 'what is this?');
my @list = map { s/this/that/; $_ } map { $_ } @orig;
# @orig unmodified