tags:

views:

160

answers:

6

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

$string="abcabdaaa";

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

+3  A: 

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/;
}
RegDwight
+6  A: 

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; 
eugene y
hi but am facing problem when am replacing by $s="***ab***c"; $s=~s{\*}{\*\n} for 1..2; print$s; it replaces first * by *\n and the rest it ignores... why? "*\n" **ab***c
lokesh
If I understand you correctly, you need smth like this:my $i = 0; $str =~ s/(\\*)/ ++$i > $n ? $1 : "*\n" /ge;
eugene y
+4  A: 

you can try this:

$str1=join('i',split(/a/,$str,$n));
jojo
i beleive this would be more efficient then simply doing $string =~ s/a/i/ for 1..$n;
jojo
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
you may be right about the easy to understand. but as for efficiencyusing s/a/i/ for 1..$n will take O(n*m). while using split will take O(n).
jojo
This also avoids the problem encountered when the replacement string matches the match expression.
Jeff B
+8  A: 

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.

FM
A: 

Using

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;
  }ge;

  $_;
}

You can then write

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

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

to get the following output:

[*
*
*ab***c]
Greg Bacon
Won't the output actually be: [*\n\n**ab***c] ? It will match on the first * on each iteration.
Jeff B
I posted runnable, working code. You don't have to take my word for it! :-)
Greg Bacon
+1  A: 

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

#!/usr/bin/perl

use strict; use warnings;

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

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

print "$string\n";

Output:

*
*
*
ab***c
Sinan Ünür