How do I perform multiple replacements with Perl?
Solution 1
You can use the 'e' modifier to execute code in the second part of an s///
expression.
$s =~ s/(\+)|(dog)/$1 ? ' ' : 'cat'/eg;
If $1
is true, that means the \+
matched, so it substitutes a space; otherwise it substitutes "cat".
Solution 2
Two regular expressions might make your life a lot easier:
$s =~ s/\+/ /g;
$s =~ s/dog/cat/g;
The following matches "+," followed by a bunch of stuff, followed by "dog." Also, "+" is technically a metacharacter.
/+(.*)dog/
Solution 3
Perl 5.14 and newer has the ability to chain substitutions with a non-destructive assignment so you can kill 3 birds with one stone: do your two global substitutions plus assign the result to a new variable without modifying your original variable.
my $s = "The+quick+brown+fox+jumps+over+the+lazy+dog+that+is+my+dog";
my $result = $s =~ s/+/ /gr
=~ s/dog/cat/gr;
Will replace all your +
with space and replace every dog
with cat
, assigning the result into a new variable. In a one-liner.
Solution 4
A hash may do what you want:
#!/usr/bin/perl
use strict;
use warnings;
my $s = "The+quick+brown+fox+jumps+over+the+lazy+dog+that+is+my+dog";
my %replace = (
"+" => " ",
dog => "cat",
);
$s =~ s/([+]|dog)/$replace{$1}/g;
print "$s\n";
In the comments I see that you are concerned with performance, the two regex solution is more performant. This is because any solution that works for one regex will need to use captures (which slow down the regex).
Here are the results of a benchmark:
eval: The quick brown fox jumps over the lazy cat that is my cat
hash: The quick brown fox jumps over the lazy cat that is my cat
two: The quick brown fox jumps over the lazy cat that is my cat
Rate hash eval two
hash 33184/s -- -29% -80%
eval 46419/s 40% -- -72%
two 165414/s 398% 256% --
I used the following benchmark:
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark;
my $s = "The+quick+brown+fox+jumps+over+the+lazy+dog+that+is+my+dog";
my %replace = (
"+" => " ",
dog => "cat",
);
my %subs = (
hash => sub {
(my $t = $s) =~ s/([+]|dog)/$replace{$1}/g;
return $t;
},
two => sub {
(my $t = $s) =~ s/[+]/ /g;
$t =~ s/dog/cat/g;
return $t;
},
eval => sub {
(my $t = $s) =~ s/(\+)|(dog)/$1 ? ' ' : 'cat'/eg;
return $t;
},
);
for my $k (sort keys %subs) {
print "$k: ", $subs{$k}(), "\n";
}
Benchmark::cmpthese -1, \%subs;
Solution 5
Simple answer - use 2 lines!:
$s =~ s/+/ /g;
$s =~ s/dog/cat/g;
It could probably be done in one line with 'non-greedy' matching, but this should do the trick
user332951
Updated on June 06, 2022Comments
-
user332951 about 2 years
I have Perl code:
my $s = "The+quick+brown+fox+jumps+over+the+lazy+dog+that+is+my+dog";
I want to replace every
+
with space anddog
withcat
.I have this regular expression:
$s =~ s/\+(.*)dog/ ${1}cat/g;
But, it only matches the first occurrence of
+
and lastdog
.