Reputation: 29096
Using pcre, I would like to replace all the foo
with bar
only on the lines that starts with foobar
?
Input:
foobar foo foo foo foo
foobaz foo foo foo foo foo
Output:
foobar bar bar bar bar
foobaz foo foo foo foo foo
I naively tried \K
like:
s/^foobar\Kfoo/bar/g
Unfortunately it does not work. For example, with Perl I could do:
s/^foobar(.*)/$&=~s#\bfoo\b#bar#gr/gme
Is there a way to do it, for example in https://regex101.com/?
Upvotes: 1
Views: 40
Reputation: 626845
You may combine \K
with a \G
operator in a regex:
(?m)(?:(?!^)\G|^foobar\b)(?:(?!\bfoo\b).)*\K\bfoo\b
where (?:(?!\bfoo\b).)*
tempered greedy token is synonymic to .*?
. If there is not substring to exclude in between foobar
and foo
, the .*?
will perform better, however, in case you want to further restrict the text between foobar
and foo
, you will need the token.
See the regex demo
Word boundaries might turn out redudant if you are not interested in a whole word search.
Details:
(?m)
- multiline mode on(?:(?!^)\G|^foobar\b)
- match only the end of the previous successful match (with (?!^)\G
where \G
matches the start of string or end of the previous successful match, so the (?!^)
is necessary to exclude position at the start of the string) or the whole word foobar
at the beginning of a line (^
matches the line start position due to (?m)
flag)(?:(?!\bfoo\b).)*
- match any char other than linebreak symbols, 0+ times, if the char is not starting the foo
sequence that is a whole word (or instead just replace this part with .*?
since there is no text to exclude in between foobar
and foo
).\K
- omit the text matched so far \bfoo\b
- a whole word foo
Upvotes: 1
Reputation: 89557
yes, with this \G (position after the previous match or start of the string) based pattern:
(?:\G(?!\A)|(?m)^foobar\b).*?\K\bfoo\b
Upvotes: 1