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

Hi, I'm new to Perl, and I'm just wandering if Perl can do only a given number of replacements, instead of only one ( s/a/B/ ) or all of them ( s/a/B/g ). Say I have a string: code$x="ababababab"/code and I want to replace only the first three occurrences of "a" with "B", is there a quick command such as ... illustration only code perl -e '$x="ababababab"; $x =~ s/a/B/3; print $x . "\n"' BbBbBbabab /code Thanks
  • Comment on Does Perl support a given number of replacements ?

Replies are listed 'Best First'.
Re: Does Perl support a given number of replacements ?
by jwkrahn (Abbot) on Jun 06, 2009 at 01:47 UTC
Re: Does Perl support a given number of replacements ?
by Anonymous Monk on Jun 06, 2009 at 00:33 UTC
    loop
    $_ = 'a a a a a a a a'; my $i = 3; while($i){ $i--; s/a/B/; } print "$_\n"; __END__ B B B a a a a a

      or, a little more concisely...

      $s =~ s/a/B/ for(1..3);
        I think ig's reply and also Re: Does Perl support a given number of replacements ? have a bug. Consider:
        >perl -wMstrict -le "my $x = 'aBaCaDaEaFa'; $x =~ s/a/aa/ for 1 .. 3; print $x; "
        If I run this code, I might expect  'aaBaaCaaDaEaFa' to be printed, but I get  'aaaaBaCaDaEaFa' instead. This is because the regex of the substitution does not 'remember' its position in the string being searched, but instead starts from the beginning of the string on each invocation. So, if the substituted portion of the string contains anything that may be matched by the regex, then it, and not anything further along in the string, is what will be (repeatedly) replaced.

        jwkrahn's reply Re: Does Perl support a given number of replacements ? shows a way around this.

        Update: Improved first example and changed pertinent discussion, removed a second example as no longer offering greater clarity.

        Wonderful !!! That's exactly what I was thinking of :)) Thanks.
      A nice one. I use a similar code with awk. I had the impression that Perl might have a ready-made construct that works right out of the box. Thanks.
      There is a catch though. If 'B' contains 'a', (or the replacement of an 'a' to a 'B' creates a new 'a'), this doesn't quite do what you want. A simple case, assume 'a' is '\w' and 'B' is just 'B'. Then
      $_ = 'pqrstuvw'; my $i = 3; while($i) { $i--; s/\w/B/; } print "$_\n"; __END__ Bqrstuvw
Re: Does Perl support a given number of replacements ?
by JavaFan (Canon) on Jun 06, 2009 at 16:42 UTC
    I think this will work in all cases:
    $x = join 'B', split /a/, $x, 4;
Re: Does Perl support a given number of replacements ?
by furry_marmot (Pilgrim) on Jun 07, 2009 at 10:15 UTC
    Lots of good solutions here. If you can clearly isolate the thing you want to change, you can keep it pretty simple and control the number of changes with $i:
    $x = 'ababababab'; $i=3; $x =~ s/(^|[^a])a([^a]|$)/$1B$2/ while $i--; print "$x\n" __END__ BbBbBbabab
    --marmot
      Hi again, Thank you all for your time and solutions, I see that the problem becomes trickier when it comes to RE's ..., but at least now I know how Perl handles this situation. Appreciate your help. Thanks.