如何匹配仅遵循特定模式的第二个模式?

How to match all for a second pattern that follows a particular pattern only?

使用 ,我想仅在以 foobar?

开头的行上将所有 foo 替换为 bar

输入:

foobar foo   foo                  foo       foo
foobaz    foo   foo            foo   foo foo

输出:

foobar bar   bar                  bar       bar
foobaz    foo   foo            foo   foo foo

我天真地尝试 \K 喜欢:

s/^foobar\Kfoo/bar/g

不幸的是,它不起作用。例如,使用 Perl 我可以这样做:

s/^foobar(.*)/$&=~s#\bfoo\b#bar#gr/gme

有没有办法做到这一点,例如 https://regex101.com/?

您可以在正则表达式中将 \K\G 运算符结合使用:

(?m)(?:(?!^)\G|^foobar\b)(?:(?!\bfoo\b).)*\K\bfoo\b

其中 (?:(?!\bfoo\b).)* tempered greedy token.*? 同义。如果 foobarfoo 之间没有要排除的子字符串,.*? 的性能会更好,但是,如果您想进一步限制 foobarfoo,您将需要令牌。

regex demo

如果您对整个单词搜索不感兴趣,单词边界可能会变得多余。

详情:

  • (?m) - 开启多行模式
  • (?:(?!^)\G|^foobar\b) - 仅匹配上一个成功匹配的结尾((?!^)\G 其中 \G 匹配字符串的开头或上一个成功匹配的结尾,因此 (?!^) 是排除字符串开头的位置所必需的)或一行开头的整个单词 foobar^ 由于 (?m) 标志与行开始位置匹配)
  • (?:(?!\bfoo\b).)* - 匹配除换行符号以外的任何字符,0 次以上,如果字符未开始 foo 序列,即整个单词( 或者 只需将此部分替换为 .*?,因为在 foobarfoo).[=58= 之间没有要排除的文本]
  • \K - 省略目前匹配的文本
  • \bfoo\b - 一个完整的单词 foo

是的,使用此 \G (上一个匹配项之后的位置或字符串的开头) 基于模式:

(?:\G(?!\A)|(?m)^foobar\b).*?\K\bfoo\b

demo