R: (*SKIP)(*FAIL) 对于多个模式
R: (*SKIP)(*FAIL) for multiple patterns
给定 test <- c('met','meet','eel','elm')
,我需要一行代码来匹配不在 'me' 或 'ee' 中的任何 'e'。我写了 (ee|me)(*SKIP)(*F)|e
,它确实排除了 'met' 和 'eel',但不包括 'meet'。这是因为 |
是独占的还是?无论如何,有没有解决方案 returns 'elm'?
郑重声明,我知道我也可以 (?<![me])e(?!e)
,但我想知道 (*SKIP)(*F)
的解决方案是什么以及为什么我的行是错误的。
您可以在您的第一个模式中添加 \w*
以帮助引擎处理更多数据,告知 ee
或 me
可以出现在字符串的开头、中间或结尾.
您可以像这样使用正则表达式:
\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"
您需要一个 preceding/following 边界来强制正则表达式引擎不重试子字符串。
gsub('\w*[em]e\w*(*SKIP)(?!)|e', '', test, perl=T)
或者正如@CasimiretHippolyte 指出的那样——前面有一个可选的 "e" ...
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)(?!)
这是 (*SKIP)(*F)
的正确解决方案:
(?:me+|ee+)(*SKIP)(*FAIL)|e
Demo on regex101,使用以下测试用例:
met
meet
eel
elm
degree
zookeeper
meee
只有elm
中的e
,degree
中的第一个e
和zookeeper
中的最后一个e
匹配。
由于ee
中的e
是禁止的,所以m
之后的任何e
都是禁止的,并且连续[=的子串中的任何e
18=] 被禁止。这解释了子模式 (?:me+|ee+)
.
虽然我知道此方法不可扩展,但至少在逻辑上是正确的。
其他方案分析
解决方案 0
(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
可以匹配。
解决方案 1
\w*(ee|me)\w*(*SKIP)(*FAIL)|e
这将跳过所有包含 ee
和 me
的单词,这意味着它将无法匹配 degree
和 zookeeper
.
中的任何内容
解决方案 2
(?:ee|mee?)(*SKIP)(?!)|e
与解决方案0类似的问题。当连续3个e
时,前2个e
被mee?
匹配,剩下第三个e
可用用于匹配。
解决方案 3
(?:^.*[me]e)(*SKIP)(*FAIL)|e
这将丢弃直到最后一个 me
或 ee
的输入,这意味着最后一个 me
或 ee
之前的任何有效 e
不会被匹配,比如 degree
.
中的第一个 e
给定 test <- c('met','meet','eel','elm')
,我需要一行代码来匹配不在 'me' 或 'ee' 中的任何 'e'。我写了 (ee|me)(*SKIP)(*F)|e
,它确实排除了 'met' 和 'eel',但不包括 'meet'。这是因为 |
是独占的还是?无论如何,有没有解决方案 returns 'elm'?
郑重声明,我知道我也可以 (?<![me])e(?!e)
,但我想知道 (*SKIP)(*F)
的解决方案是什么以及为什么我的行是错误的。
您可以在您的第一个模式中添加 \w*
以帮助引擎处理更多数据,告知 ee
或 me
可以出现在字符串的开头、中间或结尾.
您可以像这样使用正则表达式:
\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"
您需要一个 preceding/following 边界来强制正则表达式引擎不重试子字符串。
gsub('\w*[em]e\w*(*SKIP)(?!)|e', '', test, perl=T)
或者正如@CasimiretHippolyte 指出的那样——前面有一个可选的 "e" ...
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)(?!)
这是 (*SKIP)(*F)
的正确解决方案:
(?:me+|ee+)(*SKIP)(*FAIL)|e
Demo on regex101,使用以下测试用例:
met
meet
eel
elm
degree
zookeeper
meee
只有elm
中的e
,degree
中的第一个e
和zookeeper
中的最后一个e
匹配。
由于ee
中的e
是禁止的,所以m
之后的任何e
都是禁止的,并且连续[=的子串中的任何e
18=] 被禁止。这解释了子模式 (?:me+|ee+)
.
虽然我知道此方法不可扩展,但至少在逻辑上是正确的。
其他方案分析
解决方案 0
(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
可以匹配。
解决方案 1
\w*(ee|me)\w*(*SKIP)(*FAIL)|e
这将跳过所有包含 ee
和 me
的单词,这意味着它将无法匹配 degree
和 zookeeper
.
解决方案 2
(?:ee|mee?)(*SKIP)(?!)|e
与解决方案0类似的问题。当连续3个e
时,前2个e
被mee?
匹配,剩下第三个e
可用用于匹配。
解决方案 3
(?:^.*[me]e)(*SKIP)(*FAIL)|e
这将丢弃直到最后一个 me
或 ee
的输入,这意味着最后一个 me
或 ee
之前的任何有效 e
不会被匹配,比如 degree
.
e