regex 为什么在使用Python的re模块时顺序为“a+| A+”与“A+| a+”事项?[副本]

vptzau2j  于 2022-11-18  发布在  Python
关注(0)|答案(2)|浏览(93)

此问题在此处已有答案

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的实现有关。

gopyfrb3

gopyfrb31#

@Kaz关于Python正则表达式的有序选择语义当然是正确的,但这不是这里的问题。连接没有交替紧密,所以没有A+|a+子模式,因为A+|a+.*a+意味着(A+)|(a+.*a+)。类似地,a+|A+.*a+意味着(a+)|(A+.*a+)。它们显然匹配不同的字符串。第一个不匹配pineapple,因为它要查找一个A或两个a;第二个匹配pineapple,因为它将匹配一个a或者一个同时包含Aa的字符串。两个使用A的测试也包含a。因此您的测试也需要做一些工作。
我想你是想用(A+|a+).*a+。如果你是这样想的,你可能要考虑使用[Aa]+.*a+,甚至[Aa]+.*[Aa]+,尽管它有一点语义上的差异。但它仍然是不正确的。
我不明白强制重复运算符+的用法。您是说Aarhus不应该通过,因为两个A是连续的吗?如果是这样,您应该更接近[Aa]+.*a+,因为它将匹配AaA+|a+将匹配AAaa。但是给定输入Aarhus,它只匹配A,剩下arhus要与模式的其余部分.*a+匹配,这将成功,因为.*将匹配空字符串。
在任何情况下,都不需要重复+。如果你想匹配Aarhus,那么你可以使用[Aa].*[Aa],它匹配一个包含两个a的单词。如果你想坚持有两个a的聚类,那么Aarhus不匹配,而aardvark匹配,那么你可以使用[aA][^aA].*[aA]。如果在两个X1 M40 N1 X之间存在至少一个非X1 M39 N1 X,则该值匹配。

4ioopgfo

4ioopgfo2#

基于回溯搜索的正则表达式实现往往有一个有趣的|操作符,它的顺序很重要,因为它们是按从左到右的顺序尝试替代项的。编译成等价的NFA/DFA的正则表达式就没有这个怪癖。
它不会对确定基本问题产生影响:给定的输入字符串是否属于正则表达式所表示的字符串集?
但是,它与部分匹配有所不同:给定A|B,如果AB两者独立地匹配S的前缀,但是长度不同,则组合的正则表达式A|B必须匹配两者中较长的一个;但是从左到右尝试替换项的回溯实现将在A处停止。它也可以尝试B并跟踪哪个是较长的匹配,但是这将使它变慢。

相关问题