鉴于test <- c('met','meet','eel','elm')
,我需要一行代码来匹配任何不在'me'或'ee'中的e。我写了(ee|me)(*SKIP)(*F)|e
,它确实排除了'met'和'eel',但没有'meet'。这是因为|
是独占还是?无论如何,是否有一种解决方案只能返回“榆树”?
为了记录,我知道我也可以(?<![me])e(?!e)
,但我想知道(*SKIP)(*F)
的解决方案是什么以及为什么我的行错了。
答案 0 :(得分:5)
这是(*SKIP)(*F)
的正确解决方案:
(?:me+|ee+)(*SKIP)(*FAIL)|e
Demo on regex101,使用以下测试用例:
met
meet
eel
elm
degree
zookeeper
meee
仅e
elm
,e
中的degree
和e
中的最后zookeeper
匹配。
由于e
中的ee
被禁止,e
之后的任何m
都被禁止,并且连续{{1}的子字符串中的任何e
都被禁止} 禁止。这解释了子模式e
。
虽然我知道这种方法不可扩展,但它至少在逻辑上是正确的。
(?:me+|ee+)
我们以(ee|me)(*SKIP)(*F)|e
为例:
meet
问题是由于meet # (ee|me)(*SKIP)(*F)|e
^ # ^
meet # (ee|me)(*SKIP)(*F)|e
^ # ^
meet # (ee|me)(*SKIP)(*F)|e
^ # ^
# Forbid backtracking to pattern to the left
# Set index of bump along advance to current position
meet # (ee|me)(*SKIP)(*F)|e
^ # ^
# Pattern failed. No choice left. Bump along.
# Note that backtracking to before (*SKIP) is forbidden,
# so e in second branch is not tried
meet # (ee|me)(*SKIP)(*F)|e
^ # ^
# Can't match ee or me. Try the other branch
meet # (ee|me)(*SKIP)(*F)|e
^ # ^
# Found a match `e`
消耗了第一个me
,因此e
无法匹配,第二个ee
可用于匹配。
e
这只会跳过\w*(ee|me)\w*(*SKIP)(*FAIL)|e
和ee
的所有字词,这意味着它无法匹配me
和degree
中的任何字词。
zookeeper
与解决方案0类似的问题。当一行中有3 (?:ee|mee?)(*SKIP)(?!)|e
时,前{2} e
与e
匹配,第三mee?
可用于匹配
e
这会将输入丢弃到最后(?:^.*[me]e)(*SKIP)(*FAIL)|e
或me
,这意味着在最后ee
或e
之前的任何有效me
都不会匹配,就像ee
中的第一个e
一样。
答案 1 :(得分:4)
您需要前/后边界强制正则表达式引擎不重试子字符串。
gsub('\\w*[em]e\\w*(*SKIP)(?!)|e', '', test, perl=T)
或者@CasimiretHippolyte指出 - 前面有一个可选的&#34; e&#34; ...
gsub('(?:ee|mee?)(*SKIP)(?!)|e', '', test, perl=T)
每次评论更新(使用量词(用于其他案例)):
gsub('[em]e+(*SKIP)(?!)|e', '', test, perl=T)
注意:我决定使用(?!)
代替(*F)
,这也用于强制正则表达式失败。
(?!) # equivalent to ( (*FAIL) or (*F) - both synonyms for (?!) ),
# causes matching failure, forcing backtracking to occur
总体而言,语法可以写为(*SKIP)(*FAIL)
,(*SKIP)(*F)
或(*SKIP)(?!)
答案 2 :(得分:3)
您可以在第一个模式中添加\w*
,以便为引擎提供更多数据,告知ee
或me
可以出现在字符串的开头,中间或末尾。< / p>
你可以使用这样的正则表达式:
\w*(ee|me)\w*(*SKIP)(*FAIL)|e
R正则表达式,
> test <- c('met','meet','eel','elm')
> gsub("\\w*(?:ee|me)\\w*(*SKIP)(*FAIL)|e", "fi", perl=TRUE, test)
[1] "met" "meet" "eel" "film"
或强>
> gsub('(?:^.*[me]e)(*SKIP)(*FAIL)|e', 'fi', test, perl=T)
[1] "met" "meet" "eel" "film"
<强> Working demo 强>