Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

Swap foo and bar in text?

by Cody Fendant (Friar)
on Apr 18, 2012 at 04:36 UTC ( #965610=perlquestion: print w/replies, xml ) Need Help??
Cody Fendant has asked for the wisdom of the Perl Monks concerning the following question:

Say I wanted to do this:

    $str =~ s/foo/bar/g;

    $str =~ s/bar/foo/g;

I would obviously have a problem, because a "foo" in the original would be changed back to a "foo". by the second replacement.

The way I do it manually in a text/WP app is:

    $str =~ s/foo/%%%/g; # or any other extremely unlikely string

    $str =~ s/bar/foo/g;

    $str =~ s/%%%/bar/g;

but is there a better way to do it?

    $str =~ s/(foo|bar)/$1 eq 'foo'?'bar':'foo';/ge;

works, and benchmarks better than the other way (string with 1,000 chars). Anything else monks can suggest?
percentage_way: 130 wallclock secs (126.01 usr + 0.29 sys = 126.30 CP +U) @ 7917.66/s (n=1000000) rhs_way: 49 wallclock secs (46.50 usr + 0.13 sys = 46.63 CPU) @ 21 +445.42/s (n=1000000)

Replies are listed 'Best First'.
Re: Swap foo and bar in text?
by davido (Archbishop) on Apr 18, 2012 at 04:46 UTC

    I don't know how it benchmarks, and would need to be convinced that it matters. ;) However, here is another way to do it.

    my %swaps = ( foo => 'bar', bar => 'foo' ); $str =~ s/(foo|bar)/$swaps{$1}/g


      It benchmarks marginally better than the "percentage" method but still way slower than the "evaluated right hand side" method.
Re: Swap foo and bar in text?
by GrandFather (Sage) on Apr 18, 2012 at 05:00 UTC

    I'd be inclined to use a lookup for the text to be replaced then use a regex driven substitution to do the heavy lifting:

    #!/usr/bin/perl use strict; use warnings; my %edits = (foo => 'bar', bar => 'foo'); my $value = 'This string is all barfoo, but a little Perl should swap +the foos and bars'; my $match = '(' . join ('|', keys %edits) . ')'; $value =~ s/$match/$edits{$1}/g; print $value;


    This string is all foobar, but a little Perl should swap the bars and +foos
    True laziness is hard work

      Assuming "foo" and "bar" are metasyntactic variables, and that the real substrings could be anything, the use of quotemeta is in order:

      UPDATE: This paragraph should readů

      Assuming "foo" and "bar" are metasyntactic variables representing literal substrings, and that the real literal substrings could be any literal substrings (not regular expression patterns), then the use of quotemeta is in order:
      #!/usr/bin/perl use strict; use warnings; my %edits = ( '***' => 'stars', '|||' => 'stripes' ); my $value = '*** and |||'; my $match = '(' . join('|', map { quotemeta } keys %edits) . ')'; $value =~ s/$match/$edits{$1}/g; print $value; # Prints "stars and stripes"

      (I realize this example is no longer swapping anything. Sorry.)


        the real substrings could be anything

        Indeed, which is why I removed the quote meta code from the example code before posting it - anything could include regular expressions which don't work so well when quoted.

        True laziness is hard work

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://965610]
Approved by GrandFather
Front-paged by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (8)
As of 2018-06-24 03:57 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (126 votes). Check out past polls.