为什么 \K 似乎消耗了基 R 的 gsub 中的一个字符

Why does \K appear to consume a character in base R's gsub

这是一个示例字符串:'bcadefgh'.
我希望我可以使用以下模式匹配除 'cad' 之外的所有内容:'\wa\w\K|\w'.
如果我想替换所有不是 'cad' 的东西,我可以使用 gsub,就像 gsub('\wa\w\K|\w', '', 'bcadefgh', perl = TRUE),但是这会输出 'cade'

gsub(pattern = '\wa\w\K|\w', replacement = '', 'bcadefgh', perl = TRUE)
# [1] "cade"

我的预期是 \K 会在 'cad' 中的 'd' 之后导致重置,类似于 '\wa\w(*SKIP)(*F)|\w',因此,应该匹配以下 'e' 并且代替了。相反,在我看来 \K 正在消耗一个字符并在 'e' 之后重新启动匹配过程。我是不是误会了?

使用 regex101 (flavor: pcre),我得到了我所期望的:除了 'cad' 之外的所有内容都匹配。

使用 ore 包(Oniguruma 正则表达式,而不是 pcre),我也得到了预期的输出:

ore::ore_subst(regex = '\wa\w\K|\w',
               replacement = '',
               text = 'bcadefgh',
               all = TRUE)
# [1] "cad"

如果我回到 gsub 但对 'a' 之后的单词字符使用零宽度正前瞻而不是使用它((?=\w) 而不是 \w ):

gsub('\wa(?=\w)\K|\w', '', 'bcadefgh', perl = TRUE)
# [1] "cad"

我得到了想要的输出,但我不清楚为什么会这样。

对此行为的解释是什么?

Advancing After a Zero-Length Regex Match:

The regexp functions in R and PHP are based on PCRE, so they avoid getting stuck on a zero-length match by backtracking like PCRE does. But the gsub() function to search-and-replace in R also skips zero-length matches at the position where the previous non-zero-length match ended, like Python does.

引擎在遇到 zero-length 匹配的意义上有所不同。乍一看,似乎 运行 像 \s*|\S+ 这样的正则表达式在输入字符串(例如 hello 上应该 return 2 匹配:

第一场比赛(zero-length 比赛就在 h 之前):

¦h e l l o 
^

第二个匹配(整个单词):

hello 
>>>>>

人是这样想的。从正则表达式引擎的角度来看,事实并非如此。 well-known 引擎像 PCRE return 的三个匹配项(前两个匹配项和一个 zero-length 匹配 \s* 在最后一个字符之后)但是 javascript 或 Python return 6. 因为引擎在找到 zero-length 匹配项时会跳过下一个非常直接的单个字符。

¦h¦e¦l¦l¦o¦ 
^ ^ ^ ^ ^ ^

所以引擎只满足于 \s* 部分。 gsub 以同样的方式工作。