Reputation: 7143
I have a scenario in which I need to replace the nth sub-string in a string.
s/sub-string/new-string/g;
will replace all the sub strings, but I need to do for a particular occurrence.
Please help me with this.
Upvotes: 3
Views: 8232
Reputation: 1
See perlvar for @-
and @+
.
my $str= "one two three four five";
if ( $str =~ /(?: (\w+) .*? ){3}/x ) {
substr $str, $-[1], $+[1] - $-[1], "-c-e-n-s-o-r-e-d-";
}
print $str, "\n";
The regex finds the 3rd instance, and captures its start-word in $1.
Upvotes: 0
Reputation: 23095
For replacing the nth occurrence of a string using sed
, you can use this command:
sed 's/find_string/replace_string/n'
For replacing the substring, we need to know what you want to replace. Give an example.
Upvotes: 3
Reputation: 13942
I'm really a believer that there's no point building extra complexity into a regular expression unless it's truly necessary to do so (or unless you're just having fun). In code I actually planned to use I would keep it simple, like this:
my $string = "one two three four five";
$string =~ m/\w+\s*/g for 1 .. 2;
substr( $string,pos($string) ) =~ s/(\w+)/3/;
print "$string\n";
Using the m//g
in scalar context causes it to match one time per iteration of the for
loop. On each iteration pos()
keeps track of the end of the most recent submatch on $string
. Once you've gone through 'n' iterations (two in this case), you can plug pos()
into substr()
. Use substr($string...
as an lvalue. It will constrain the regexp match to begin at whatever position you tel it in the second arg. We're plugging pos
in there, which constrains it to take its next match wherever the last match left off.
This approach eliminates an explicit counter (though the for loop is essentially the same thing without naming a counter variable). This approach also scales better than a s//condition ? result : result/eg
approach because it will stop after that third match is accomplished, rather than continuing to try to match until the end of a potentially large string is reached. In other words, the s///eg
approach doesn't constrain the matching, it only deals conditionally with the outcome of an arbitrarily large number of successful matches.
In a previous question on the same topic I once embedded a counter in the left side of the s/// operator. While it worked for that specific case, it's not an ideal solution because it's prone to being thrown off by backtracking. That's another case where keeping it simple would have been the best approach. I mention it here so that you can avoid temptation to try such a trick (unless you want to have fun with backtracking).
The approach I've posted here, I believe is very clear; you look at it and know what's happening: match twice, keep track of last match position, now match a third time with substitution. You can have clever, you can have efficient, and you can have clear. But sometimes you can't have all three. Here you get efficient and clear.
Upvotes: 1
Reputation: 5308
You can also do like this
my $i=0;
s/(old-string)/++$i%3 ? $1 : "new_string"/ge;
Upvotes: 1
Reputation: 67900
This question might be interesting: Perl regex replace count
You might do something like this:
use strict;
use warnings;
my $count = 3;
my $str = "blublublublublu";
$str =~ s/(lu)/--$count == 0 ? "LA":$1/ge;
print $str;
Upvotes: 1
Reputation: 9340
Try this:
s/(sub-string{2,2})sub-string/$1new-string/
adjust 2 according to your needs (it's your 'n'- 1). Note that there may no separators exist between those substrings. e.g. 'abcabcabc' would work but 'abcdefabcabc' won't
Upvotes: 1