Take the 2-minute tour ×

How can I search and replace a match with specific number of times using s///;. For example:


I want to replace a with i in $string n times. How can I do that? n is an integer provided by user.

share|improve this question
Answers to this question are also being provided at another forum: perlmonks.org/?node_id=820332 –  toolic Jan 29 '10 at 13:52
Can you explain a bit more about what you are doing? You have a bit of an XY problem here. Tell use the real problem you are trying to solve instead of the potential solution you think is the answer. :) –  brian d foy Jan 29 '10 at 20:16

6 Answers 6

The simple answer probably doesn't do want you want.

my $str = 'aaaa';
$str =~ s/a/a_/ for 1..2;
print $str, "\n"; # a__aaa. But you want a_a_aa, right?

You need to count the replacements yourself, and act accordingly:

$str = 'aaaa';
my $n = 0;
$str =~ s/(a)/ ++$n > 2 ? $1 : 'a_' /ge;
print $str, "\n";

See the FAQ, How do I change the Nth occurrence of something? for related examples.

share|improve this answer

Just substitute $n times:

$string =~ s/a/i/ for 1..$n;

This will do it.
More general solution would be global substitution with counter:

my $i = 0; # count the substitutions made
$string =~ s/(a)/ ++$i > $n ? $1 : "i" /ge; 
share|improve this answer
hi but am facing problem when am replacing by $s="abc"; $s=~s{*}{*\n} for 1..2; print$s; it replaces first * by \n and the rest it ignores... why? "*\n" abc –  lokesh Jan 29 '10 at 13:37
If I understand you correctly, you need smth like this: my $i = 0; $str =~ s/(\*)/ ++$i > $n ? $1 : "*\n" /ge; –  eugene y Jan 29 '10 at 14:50

I'm not aware of any flag that would do that. I'd simply use a loop:

for (my $i = 0; $i < $n; $i++)
   $string =~ s/a/i/;
share|improve this answer

you can try this:

share|improve this answer
i beleive this would be more efficient then simply doing $string =~ s/a/i/ for 1..$n; –  jojo Jan 29 '10 at 11:36
Please explain why you believe it is more efficient. You unnecessarily create 2 extra temporary variables ($str1 and @arr). You could simplify it as $str = join 'i', split /a/, $str, $n;, but I don't think that is nearly as easy to understand as the s/// solution. –  toolic Jan 29 '10 at 13:33
you may be right about the easy to understand. but as for efficiency using s/a/i/ for 1..$n will take O(n*m). while using split will take O(n). –  jojo Jan 29 '10 at 13:39
This also avoids the problem encountered when the replacement string matches the match expression. –  Jeff B Jan 29 '10 at 20:27

Here is a way to do based on the comment you made to eugene y's answer


use strict; use warnings;

my $string = '***ab***c';
my $n = 3;

1 while $n -- and $string =~ s/\*([^\n])/*\n$1/;

print "$string\n";


share|improve this answer


sub substitute_n {
  my $n = shift;
  my $pattern = shift;
  my $replace = shift;
  local $_ = shift;

  my $i = 1;
  s{($pattern)} {
    $i++ <= $n ? eval qq{"$replace"} : $1;


You can then write

my $s = "***ab***c";

print "[", substitute_n(2, qr/\*/, '$1\n', $s), "]\n";

to get the following output:

share|improve this answer
Won't the output actually be: [\n\nabc] ? It will match on the first * on each iteration. –  Jeff B Jan 29 '10 at 20:25
I posted runnable, working code. You don't have to take my word for it! :-) –  Greg Bacon Jan 29 '10 at 20:49

Your Answer


