【问题标题】:Why does the order of expressions matter in re.match?为什么表达式的顺序在 re.match 中很重要?
【发布时间】:2021-11-30 23:52:20
【问题描述】:

我正在创建一个函数,它将接受像“three()”或类似“{1 + 2}”这样的字符串并将它们放入令牌列表中(例如:“three()”= [“three ", "(", ")"] 我使用 re.match 来帮助分隔字符串。

def lex(s):
# scan input string and return a list of its tokens
seq = []
patterns = (r"^(\t|\n|\r| )*(([a-z])*|[0-9]|\(|\)|\*|\/|)(\t|\n|\r| )*")
m = re.match(patterns,s)
while m != None:
    if s == '':
        break
    seq.append(m.group(2))
    s = s[len(m.group(0)):]
    m = re.match(patterns,s)
return seq

如果字符串只是“三”,则此方法有效。但是如果字符串包含“()”或任何符号,它就会停留在 while 循环中。 但是当在模式字符串中移动 ([a-z])* 时会发生一件有趣的事情。为什么会这样?

works: patterns = (r"^(\t|\n|\r| )*([0-9]|\(|\)|\*|\/|([a-z])*)(\t|\n|\r| )*")
Does not work: patterns = (r"^(\t|\n|\r| )*(([a-z])*|[0-9]|\(|\)|\*|\/)(\t|\n|\r| )*")

【问题讨论】:

    标签: python python-3.x python-re


    【解决方案1】:

    这个有点棘手,但问题在于这部分([a-z])*。这匹配任何大小为 0(零)或更大的小写字母字符串。

    如果你把这个序列放在最后,就像这里:

    patterns = (r"^(\t|\n|\r| )*([0-9]|\(|\)|\*|\/|([a-z])*)(\t|\n|\r| )*")
    

    正则表达式引擎将首先尝试其他匹配项,如果找到匹配项,则停止。只有当其他人都不匹配时,它才会尝试([a-z])*,并且由于* 是“贪婪的”,它将匹配所有three,然后继续匹配(,最后匹配)

    阅读有关如何测试完整表达式的说明in the documentation(感谢@kaya3)。

    但是,如果您将该序列作为开头,如下所示:

    patterns = (r"^(\t|\n|\r| )*(([a-z])*|[0-9]|\(|\)|\*|\/)(\t|\n|\r| )*")
    

    它现在将首先尝试匹配它。它仍然是贪婪的,所以three 仍然匹配。但在下一次尝试中,它会尝试将([a-z])* 与剩余的'()' 匹配——并且它匹配,因为该字符串以零字母开头。

    它一直像那样匹配它,并陷入循环中。您可以通过将 * 更改为 + 来修复它,该 + 只有在有 1 个或多个匹配项时才会匹配:

    patterns = (r"^(\t|\n|\r| )*(([a-z])+|[0-9]|\(|\)|\*|\/)(\t|\n|\r| )*")
    

    【讨论】:

    • 是胡子,不是吗……?叹。不过不客气。随意点击复选标记而不是亲吻来接受答案,这样问题就会显示为已回答并可以帮助其他人。
    • 建议的文档引用:"扫描目标字符串时,REs 用 '|' 分隔从左到右尝试。” (link) - 只是为了直接回答为什么顺序很重要。
    猜你喜欢
    • 2013-08-03
    • 2013-05-18
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    相关资源
    最近更新 更多