以下是一个示例字符串:'\\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"
一样,但这会输出'\\wa\\w(*SKIP)(*F)|\\w'
ore
我的期望是\ K会在' d之后导致重置。在' cad'类似于ore::ore_subst(regex = '\\wa\\w\\K|\\w',
replacement = '',
text = 'bcadefgh',
all = TRUE)
# [1] "cad"
,因此,以下' e'应该匹配和替换。相反,在我看来,\ K正在消耗一个角色并在“e”之后重新开始匹配过程。我误解了这个吗?
regex101 (flavor: pcre),我得到了我的期望:除了' cad'匹配。
使用gsub
包(Oniguruma正则表达式,而不是pcre),我也得到了预期的输出:
(?=\\w)
如果我回到\\w
,但对于' a'后面的单词字符使用零宽度正向前瞻。而不是消费它(gsub('\\wa(?=\\w)\\K|\\w', '', 'bcadefgh', perl = TRUE)
# [1] "cad"
而不是{{1}}):
{{1}}
我得到了所需的输出,但我不清楚为什么会这样。
这种行为的解释是什么?
答案 0 :(得分:3)
Advancing After a Zero-Length Regex Match:
R和PHP中的regexp函数基于PCRE,因此它们可以避免 像PCRE那样通过回溯卡在零长度的比赛上。 但是在R中搜索和替换的
gsub()
函数也会跳过 零长度匹配在前一个非零长度的位置 匹配结束,就像Python一样。
引擎在遇到零长度匹配方面有所不同。乍一看似乎在\s*|\S+
之类的输入字符串上运行正如hello
这样的正则表达式应该返回2个匹配项:
第一场比赛(h
之前的零长度比赛):
¦h e l l o
^
第二场比赛(全字):
hello
>>>>>
人类就是这样想的。从正则表达式引擎的角度来看,情况并非如此。像PCRE这样的知名引擎会在最后一个字符后返回三个匹配项(前两个匹配项和\s*
之间的零长度匹配项)但javascript或Python返回6.因为引擎会在零时跳过下一个非常直接的单个字符找到了长度匹配。
¦h¦e¦l¦l¦o¦
^ ^ ^ ^ ^ ^
所以引擎只用\s*
部分来满足自己。 gsub
以同样的方式运作。