此问题在此处已有答案:
Why order matters in this RegEx with alternation?(3个答案)
昨天关闭。
''' The repeating_letter_a function checks if the text passed
includes the letter "a" (lowercase or uppercase) at least twice.
For example, repeating_letter_a("banana") is True, while
repeating_letter_a("pineapple") is False. '''
import re
def repeating_letter_a(text):
# result = re.search(r"A+|a+.*a+", text) <-- this works fine
# result = re.search(r"a+|A+.*a+", text) <-- this does not
return result != None
# These test cases include the desired outcomes:
print(repeating_letter_a("banana")) # True
print(repeating_letter_a("pineapple")) # False
print(repeating_letter_a("Animal Kingdom")) # True
print(repeating_letter_a("A is for apple")) # True
我能够生成工作的代码,但我很困惑为什么“A+”的顺序|a+”与“a+|如果我在www.example.com上测试代码Regex101.com,两个版本都能正常工作,这让我觉得这与Python(或re模块)对regex的实现有关。
2条答案
按热度按时间gopyfrb31#
@Kaz关于Python正则表达式的有序选择语义当然是正确的,但这不是这里的问题。连接没有交替紧密,所以没有
A+|a+
子模式,因为A+|a+.*a+
意味着(A+)|(a+.*a+)
。类似地,a+|A+.*a+
意味着(a+)|(A+.*a+)
。它们显然匹配不同的字符串。第一个不匹配pineapple
,因为它要查找一个A
或两个a
;第二个匹配pineapple
,因为它将匹配一个a
或者一个同时包含A
和a
的字符串。两个使用A
的测试也包含a
。因此您的测试也需要做一些工作。我想你是想用
(A+|a+).*a+
。如果你是这样想的,你可能要考虑使用[Aa]+.*a+
,甚至[Aa]+.*[Aa]+
,尽管它有一点语义上的差异。但它仍然是不正确的。我不明白强制重复运算符
+
的用法。您是说Aarhus
不应该通过,因为两个A
是连续的吗?如果是这样,您应该更接近[Aa]+.*a+
,因为它将匹配Aa
。A+|a+
将匹配AA
或aa
。但是给定输入Aarhus
,它只匹配A
,剩下arhus
要与模式的其余部分.*a+
匹配,这将成功,因为.*
将匹配空字符串。在任何情况下,都不需要重复
+
。如果你想匹配Aarhus
,那么你可以使用[Aa].*[Aa]
,它匹配一个包含两个a
的单词。如果你想坚持有两个a
的聚类,那么Aarhus
不匹配,而aardvark
匹配,那么你可以使用[aA][^aA].*[aA]
。如果在两个X1 M40 N1 X之间存在至少一个非X1 M39 N1 X,则该值匹配。4ioopgfo2#
基于回溯搜索的正则表达式实现往往有一个有趣的
|
操作符,它的顺序很重要,因为它们是按从左到右的顺序尝试替代项的。编译成等价的NFA/DFA的正则表达式就没有这个怪癖。它不会对确定基本问题产生影响:给定的输入字符串是否属于正则表达式所表示的字符串集?
但是,它与部分匹配有所不同:给定
A|B
,如果A
和B
两者独立地匹配S
的前缀,但是长度不同,则组合的正则表达式A|B
必须匹配两者中较长的一个;但是从左到右尝试替换项的回溯实现将在A
处停止。它也可以尝试B
并跟踪哪个是较长的匹配,但是这将使它变慢。