正则表达式:使用行首重复匹配

Regex: repeated matches using start of line

说我想替换 2 个初始 a 之后的所有 a,并且它和前 2 个 [=13] 之间只有 a =]秒。我可以在 Vim 中使用(非常神奇 \v)正则表达式 s:\v(^a{2}a{-})@<=a:X:g:

aaaaaaaaaaa

aaXXXXXXXXX

但是,为什么 s:\v^a{2}a{-}\zsa:X:g 只替换第一个出现的地方?即,给予

aaXaaaaaaaa

我认为这是因为第一个匹配“消耗”了行的开头和前 2 个 a,因此后面的匹配只匹配行的剩余部分,永远无法匹配^ 再次。这是真的?或者更确切地说,最有教育意义的解释是什么?

P.S。这是另一个问题的最小示例。

编辑

已接受的答案更正了原始正则表达式中的错字(缺少 ^),其评论回答了以下问题:为什么 ^ 可以在回顾中“重用”,但不能在 \zs案例? (回答:lookbehind 不消耗匹配,而 \zs 消耗匹配。)

这里的要点是 (a{2}a{-})@<=a 匹配前面有两个或更多 a 字符的任何 a(请参阅最后一个 a)。在 NFA 正则表达式中,它等于 (?<=a{2,}?)a,参见 its demo

^a{2}a{-}\zsa 正则表达式匹配字符串的开头,然后是两个或更多 as,然后丢弃这个匹配的文本并匹配一个 a。因此,它无法匹配其他 a,因为 ^ 将匹配锚定在字符串的开头(并且它不允许匹配其他任何地方)。

您可能想继续使用后向构造并在其中添加 ^(如果您只想在字符串以两个 a 开头时才开始匹配):

:%s/\v(^a{2}a{-})@<=a/X/g