【发布时间】:2017-06-14 23:09:20
【问题描述】:
这是一个示例字符串:'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"
我得到了想要的输出,但我不清楚为什么会这样。
这种行为的解释是什么?
【问题讨论】:
-
当您想在匹配时跳过字符串的某些部分时,
(*SKIP)(*F)方法是最合适的,而不是\K,这是一种积极向后看的消费版本。此外,像你这样的模式可以重写为纯 TRE 正则表达式,gsub('(\\wa\\w)?\\w', '\\1', 'bcadefgh'),不需要 PCRE 正则表达式。 -
@WiktorStribiżew 感谢您的意见。这只是一个例子,说明了我对 \\K 行为方式的困惑。这个问题是针对 question 和那里的一些 cmets 而出现的,而不是需要针对这个特定示例的解决方案。