为什么 \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
以同样的方式工作。
这是一个示例字符串:'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
以同样的方式工作。