ssr1012
ssr1012

Reputation: 2589

In Perl, how can I use `s///` to make multiple replacements?

My Input:

 $brackets = '\left \right \center \right \left \middle';

On the above string I need to replace every \left string into ( opening braces and every \right string into ) closing braces.

I am able to replace in few methods to get the output. However I want to know how can we done this in r modifier. Here is what I have so far

 $brackets=~s{\\(left|right)}{$&=~s/\\left/\(/r && $&=~s/\\right/\)/gr; }ge;

I don't know where could I find my mistake.

Upvotes: 0

Views: 321

Answers (4)

user7818749
user7818749

Reputation:

It is fairly easy to just build a list of replacements.

use strict;
use warnings;

my $brackets = '\left \right \center \right \left \middle';

for ( $brackets ) {
    s/\\left/(/g;
    s/\\right/)/g;
}

print $brackets, "\n";

obviously you can still add to the list and remove whitespace as well.

More information about this method:

Upvotes: 0

Sinan Ünür
Sinan Ünür

Reputation: 118156

For this literal question which involves only two substrings to be replaced, you should use two separate s/// as @Patrick85 recommends. The approach below begins to make sense only if you have 3 or more such replacements. In that case, tucking the mapping away in a hash will make your code clearer.

Use a hash to look up replacements:

#!/usr/bin/env perl

use strict;
use warnings;

my %replacement = (
    '\left' => '(',
    '\right' => ')'
);

my $s = '\left \right \center \right \left \middle';
my $t = $s =~ s/( \\ (?: left | right ))/$replacement{$1}/rgx;

print "$s\n$t\n";

There are many problems with trying to cram everything into a single line:

$brackets=~s{\\(left|right)}{$&=~s/\\left/\(/r && $&=~s/\\right/\)/gr; }ge;

It is hard to read. Also, it is impossible to generalize. What happens if you need to map N strings to their replacements? Let's try to write this a little more clearly by adding some whitespace:

$brackets =~ s{
    \\
    (left | right)
}{
    $& =~ s/\\left/\(/r &&
    $& =~ s/\\right/\)/gr; 
}gex;

Even if this did what you wanted, you've now replaced a single s/// coupled with a simple hash lookup with something that does two additional s/// operations for each match in your source string.

For the example string you showed, this one would do eight additional s/// operations.

That is not good.

Upvotes: 6

ssr1012
ssr1012

Reputation: 2589

Just I need to close this my Question. And the answer provided by @Wiktor Stribiżew [in Comment] on my question.

$brackets = '\left \right \center \right \left \middle';

My Request:

$brackets=~s{\\(left|right)}{$&=~s/\\left/\(/r && $&=~s/\\right/\)/gr; }ge;

Answer:

$brackets=~s/\\((left)|right)/$2 ? '(' : ')'/eg;

Upvotes: -4

FrankTheTank_12345
FrankTheTank_12345

Reputation: 580

Use two simple substitutions instead of one complicated one:

#!/usr/bin/env perl
use strict;
use warnings;

my $brackets = '\left \right \center \right \left \middle';

$brackets =~ s/\\left/(/g;
$brackets =~ s/\\right/)/g;

print $brackets."\n";

Output:

( ) \center ) ( \middle

Upvotes: 5

Related Questions