twenty four merry days of Perl Feed

The new /r flag

s///r - 2011-12-13

Perl 5.14 introduced a new feature for the substitution operator to return a modified string while leaving the original alone. Normally, the substitution operator changes the bound string (if it matches) and returns the count of the number of substitutions:


1: 
 

my $count = $string =~ s/PATTERN/REPLACEMENT/g;
 

If you didn't want to change the string, you had to create a new one, often leading to this idiom:


1: 
 

( my $new = $old ) =~ s/PATTERN/REPLACEMENT/g;
 

This way, $new gets a copy and is actually the target of the s///. Instead of that, you can use the new /r flag. That idiom then changes to this similar, but different statement:


1: 
 

my $new = $old =~ s/PATTERN/REPLACEMENT/gr;
 

This binds to $old and returns the modified string to store in $new. Working out the precedence, it looks like the parentheses have shifted:


1: 
 

my $new = ( $old =~ s/PATTERN/REPLACEMENT/gr );
 

This turns out to be much more useful inside a map, where it's easy to forget that you don't get the modified string back:


1: 
 

my @new = map { s/PATTERN/REPLACEMENT/g } @old;
 

After your @new fills with 1's and 0's, you remember that you need a different last expression in the map block:


1: 
 

my @new = map { s/PATTERN/REPLACEMENT/g; $_ } @old;
 

But then, you find out that @new is the same as @old because the s/// with the aliased $_ actually changes the original data. So, you expand the block a bit:


1: 
 

my @new = map { my $s = $_; $s =~ s/PATTERN/REPLACEMENT/g; $s } @old;
 

That's ugly. So, you upgrade to Perl 5.14 to get back to almost what you had before. Once you convince your entire company to upgrade, update all of your operating systems and packages, and reinstall all the modules, the /r flag saves you a lot of hassle inside the block:


1: 
 

my @new = map { s/PATTERN/REPLACEMENT/rg } @old;
 

This is useful with printf too, where you might want to modify a string just for the output, but leaving the original alone:


1: 
2: 
3: 

 

printf "%s %s\n",
  s/PATTERN/REPLACEMENT/rg,
  s/PATTERN2/REPLACEMENT/rg;

 

With the /r flag, it's now convenient to have the s/// in the middle of larger expressions.

Gravatar Image This article contributed by: brian d foy <bdfoy@cpan.org>