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


in reply to RE: Selective substitution: not in Perl?
in thread Selective substitution: not in Perl?

That doesn't work, suppose I have the string "abacab" and want to replace the second a with an upper case A. Your regex doesn't match. How about this (untested):
#!/usr/bin/perl -w use strict; my $string = "abacab"; print "$string\n"; my $pattern = "a"; my $better = "A"; my $n=1; my $i=0; $string =~ s/($pattern)/$i == $n ? $better : $1; i++/ge; print "$string\n"

Nuance

Replies are listed 'Best First'.
RE: RE: RE: Selective substitution: not in Perl?
by atl (Pilgrim) on Aug 16, 2000 at 15:27 UTC
    Black magic! I'm really impressed, I didn' know you can put that all into the substitution pattern. /me bows to Nuance ...

    As for my solution, I was focused on the sample input given, I didn't think of the more general problem. But you're right about this.

    As for your script, it works with a small alteration:

    $string =~ s/($pattern)/$i++ == $n ? $better : $1/ge;
    If you increment $i in a seperate statement, the whole block evaluates to the value of $i und you get
    abacab 0b1c2b
    Ok, now we're having fun :-)...

    Andreas (waiting for the chinese food delivery service ...)

      To make it even clearer, remember that the right side of the s///ge can be an arbitrary block. Here's the "Perl Bowling" style written for clarity:
      { my $count = 0; $string =~ s{($pattern)}{ my $source = $1; $count++; if ($count == $target) { $source = $replacement; # replace! } $source; # either original or replacement now }ge; };
      And yes, you can actually write it like that, just as you see. If you're doing anything odd in the right hand side in a s///e, I recommend expanding it out like that.

      -- Randal L. Schwartz, Perl hacker

RE: RE: RE: Selective substitution: not in Perl?
by Anonymous Monk on Aug 17, 2000 at 01:46 UTC
    Thanks, your solution works great! I wrote a sub to convert sed-ish s///n constructs to your format, making conversion from sed easier:
    sub seval { my ($sub) = shift; $vni++; $sub =~ s#s/([^/]+)/([^/]+)/(.+)#s/\1/\$i$vni++ == \3 ? \2 : \$&/e +gs#; return $sub; } # Evals 's/foo/$i1++ == 1 ? bar : $&/egs' eval(seval("s/foo/bar/2"));
    Thanks again.