http://www.perlmonks.org?node_id=17840

whahoo has asked for the wisdom of the Perl Monks concerning the following question:

How do i find $a and replace it with $b when it's preceded by $c?

Originally posted as a Categorized Question.

  • Comment on How do i find $a and replace it with $b when it's preceded by $c?

Replies are listed 'Best First'.
Re: How do i find $a and replace it with $b when it's preceded by $c?
by nuance (Hermit) on Jun 13, 2000 at 13:01 UTC
    A postivive look behind clause in the regular expression will do what you want.
    my($a, $b, $c, $d) = qw{foo bar moo moofooyou); $d =~ s/(?<=$c)$a/$b/g;
    produces moobaryou in $d
Re: How do i find $a and replace it with $b when it's preceded by $c?
by Roy Johnson (Monsignor) on Oct 28, 2003 at 21:21 UTC
    If $c is actually a pattern, you should use the lookbehind. If you're just dealing with strings, the fastest might be some work with substr/index.
    use Benchmark; use vars qw/$a $b $c/; ($a, $b, $c) = qw/bar baz foo/; timethese(shift || 500000, { lookbehind => sub { local $_ = "foobarquux"; s/(?<=$c)$a/$b/g +}, chromatic => sub { local $_ = "foobarquux"; s/($c)$a/$1$b/g +}, chromatic2 => sub { local $_ = "foobarquux"; s/$c$a/$c$b/g }, substr => sub { local $_ = "foobarquux"; while ((my $p = index($_, "$c$a"))>=0) { substr($_, $p+length($c), length($a), $b); } }, });
    Output:
    chromatic: 11 wallclock secs (10.67 usr + 0.00 sys = 10.67 CPU) @ 46 +860.36/s (n=500000) chromatic2: 10 wallclock secs ( 8.81 usr + 0.00 sys = 8.81 CPU) @ 56 +753.69/s (n=500000) lookbehind: 10 wallclock secs ( 9.42 usr + 0.00 sys = 9.42 CPU) @ 53 +078.56/s (n=500000) substr: 4 wallclock secs ( 3.98 usr + 0.00 sys = 3.98 CPU) @ 12 +5628.14/s (n=500000)
Re: How do i find $a and replace it with $b when it's preceded by $c?
by btrott (Parson) on Jun 13, 2000 at 22:31 UTC
    <Editor's Note:>
    Here is chromatic's post to which btrott is responding.

    I prefer a simpler approach:

    s/$c$a/$c$b/g; or s/($c)$a/$1$b/g;
    Am I missing anything the lookbehind provides?

    </Editor's Note>

    All right... here's a benchmark of the two methods (lookbehind and just straight substitution). It looks like lookbehind is slightly faster, but not by a huge lot. Here's the code:

    use Benchmark; use vars qw/$a $b $c/; ($a, $b, $c) = qw/bar baz foo/; timethese(shift || 1, { lookbehind => sub { local $_ = "foobarquux"; s/(?<=$c)$a/$b/g +}, chromatic => sub { local $_ = "foobarquux"; s/($c)$a/$1$b/g +}, });
    And here are the benchmark results:
    Benchmark: timing 500000 iterations of chromatic, lookbehind... chromatic: 15 wallclock secs (14.46 usr + 0.00 sys = 14.46 CPU) lookbehind: 13 wallclock secs (11.93 usr + 0.00 sys = 11.93 CPU)
Re: How do i find $a and replace it with $b when it's preceded by $c?
by Incognito (Pilgrim) on Nov 21, 2001 at 01:24 UTC
    To summarize what's been done by chromatic, btrott and nuance, with the chromatic version using no backreferences named chromatic2, we have:
    Benchmark: timing 500000 iterations of chromatic, chromatic2, lookbehi +nd... chromatic: 18 wallclock secs (18.83 usr + 0.01 sys = 18.84 CPU) @ 265 +43.50/s chromatic2: 13 wallclock secs (13.55 usr + 0.00 sys = 13.55 CPU) @ 369 +00.37/s lookbehind: 14 wallclock secs (14.95 usr + 0.00 sys = 14.95 CPU) @ 334 +42.58/s
    for the test:
    use Benchmark; use vars qw/$a $b $c/; ($a, $b, $c) = qw/bar baz foo/; timethese(shift || 500000, { lookbehind => sub { local $_ = "foobarquux"; s/(?<=$c)$a/$b/g +}, chromatic => sub { local $_ = "foobarquux"; s/($c)$a/$1$b/g +}, chromatic2 => sub { local $_ = "foobarquux"; s/$c$a/$c$b/g } +, });
Re: How do i find $a and replace it with $b when it's preceded by $c?
by Anonymous Monk on Apr 09, 2001 at 21:40 UTC
    I did a benchmark, and the fastest solution is s/$c$a/$c$b/g. Don't use backreferences unless you have to.