正则表达式轮换命令

时间:2014-05-21 12:23:07

标签: regex regex-alternation

我设置了一个复杂的正则表达式来从一页文本中提取数据。由于某种原因,交替的顺序不是我所期望的。一个简单的例子是:

((13th|(Executive |Residential)|((\w+) ){1,3})Floor)

简单地说,我试图获得一个楼层号码,一个已知的命名楼层,作为备份,我捕获1-3个不知名的单词后跟地板以防以后再查看(我实际上使用的是一个组名识别这个,但不想混淆问题)

问题是如果字符串是

on the 13th Floor

我没有13th Floor我得到on the 13th Floor这似乎表明它与第3次轮换相匹配。我原以为它会匹配13楼。我特意设置了这个(或者我认为),优先考虑匹配的类型,只有当其他人被遗漏时,才会将模糊的匹配留给最后。当他们说Regex贪婪时我猜他们不是在开玩笑但是我不清楚如何将其设置为“贪婪”并按照我想要的方式行事。

2 个答案:

答案 0 :(得分:4)

一个自动机值得1000字:

Regular expression visualization

play with it

您的问题是您在替换中使用了贪婪的\w+子正则表达式。因为@rigderunner在他的评论中说明,NFA匹配最左边的子字符串,\w+将始终匹配Floor之前的任何内容,无论是一系列单词,还是{{1 }或13thExecutive或其中的三个。括号不会改变交替行为的方式。

因此,与您不希望匹配的最糟糕情况是:

Residential

你的正则表达式的问题在于你希望做一些实际的常规表达式无法做到的事情:如果替代方案没有解决问题,你会期望它匹配单词。由于常规语言无法跟踪状态,常规正则表达式无法表达此信息。

我实际上不确定使用某种前瞻可以帮助你在一个正则表达式中做到这一点,即使你可以,你最终会得到一个非常复杂,难以理解的甚至可能不是高效的正则表达式。

所以你可能更喜欢使用两个正则表达式,并从第二个正则表达式中获取组,以防第一个正则表达式失败:

xxxx yyyy zzz tttt Floor

如果没有匹配

((13th|Executive|Residential) +Floor)

N.B。:为避免重复自己,请查看that other answer,其中列出了有关正则表达式和NFA讲座的有趣资源。这将有助于您了解正则表达式的实际运作方式。

答案 1 :(得分:3)

首先,这是你的自由间隔模式的正则表达式:

tidied = re.compile(r"""
    (                   # $1: ...
      (                 # $2: One ... from 3 alternatives.
        13th            # Either a1of3.
      | (               # Or a2of3 $3: One ... from 2 alternatives.
          Executive[ ]  # Either a1of2.
        | Residential   # Or a2of2.
        )               # End $3: One ... from 2 alternatives.
      | (               # Or a3of3 $4: Last match from 1 to 3 ...
          (\w+)         # $5: ...
          [ ]           #
        ){1,3}          # End $4: Last match from 1 to 3 ...
      )                 # End $2: One ... from 3 alternatives.
      Floor             #
    )                   # End $1: ...
    """, re.VERBOSE)

请注意,上述模式具有无效的额外括号。这是一个功能相同的简化表达式:

tidied = re.compile(r"""
    (               # $1: One ... from 4 alternatives.
      13th          # Either a1of4.
    | Executive[ ]  # Or a2of4.
    | Residential   # Or a3of4.
    | (             # Or a4of4 $2: Last match from 1 to 3 ...
        (\w+)       # $3: ...
        [ ]         #
      ){1,3}        # End $2: Last match from 1 to 3 ...
    )               # End $1: One ... from 4 alternatives.
    Floor           #
    """, re.VERBOSE)

最左边的匹配

在所需词之前实际上有四个分组备选:Floor。前三个选项只是一个单词,但第四个选项匹配三个单词。 NFA正则表达式引擎从左到右工作,并始终尝试查找最长的最左侧匹配。在这种情况下,由于正则表达式一次遍历正则表达式一个字符,它会测试每个字符位置的所有四个选项。由于第四个选项总是可以匹配其他三个之前的两个单词,因此它将始终首先匹配(假设在给定文本中有{3}之前的三个单词。)。如果Floor之前没有三个单词,那么前三个选项中的一个可以匹配。

另请注意,Floor13th替代品之后没有必要的空格,因此只有在显示带有连接文字的文字时才会匹配:Residential或{{1} }。