带有嵌套组和点的正则表达式导致古怪的匹配

Regex with nested group and dot causes wacky matching

我无法理解为什么以下正则表达式和文本会产生结果。我在 notepad++ 中使用正则表达式查找函数,没有 Wrap_around 也没有匹配的换行符。正则表达式:

name ="[\w]+\.((?:[\w]*\.?)+)" p

应用于文本时:

name ="data.messageHeader.msg_time_tag.$date" pzb

this is line 2

整个文本最终突出显示,这应该是不可能的,因为正则表达式不应该能够匹配美元符号或 newline/carriage return.

我也尝试过将正则表达式应用于 python 're' 的文本。在这种情况下,我逐行解析了整个文件。最初,python 没有正确匹配带有美元符号的行,但这些行需要几秒钟才能完成,即使它们只有大约 100 个字符。在包含我的示例结构的第四行或第五行,其中以点分隔的单词包含一个“$”,python 冻结,直到我手动停止它。

使用的python代码:

import re
def main():
    pattern = re.compile(r"name =\"\w+\.((?:\w+\.?)+)\" p")
    with open(r"filepath", "r") as f:
        i = 0
        for line in f:
            match = pattern.search(line)
            if (match):
                print('<Match: %r, groups=%r>' % (match.group(), match.groups()))
            else:
                print("line %d nomatch" % (i))
            i+=1
            match = None
            #it = pattern.finditer(f.read())
            #for element in it:
                #displaymatch(element)
    
def displaymatch(match):
    if match is None:
        return None
    print('<Match: %r, groups=%r>' % (match.group(), match.groups()))    
main()

你能解释一下为什么会这样吗?

在选择文本之前,我在 Notepad++ 中停顿了很长时间,这表明它陷入了无限循环,而选择所有文本只是它在这样的循环中跳出时的默认行为。

现在,由于这部分 (?:[\w]*\.?) 可以折叠成空,并且可以出现一次或多次,我猜它只是重复匹配任何内容,直到找到匹配 $ 的内容。

name ="[\w]+\.((?:[\w$]*\.?)+)" p 似乎工作正常。

更新: 这似乎可以解决您的问题:

name ="\w+\.(?:(\w+\.)*\w+)" p

既然你想知道为什么你的模式不起作用,这里是它的细分:

name ="        - capture a literal string: `name ="`

\w+            - ... followed by one or more word characters (A-Za-z0-9_)

\.             - ... followed by a literal dot

(              - start a capturing group (following matches will be captured as a group)

    (?:        - start a non-capturing group

        \w+    - match one or more word characters (A-Za-z0-9_)
        \.?    - ... optionally followed by a literal dot

    )+         - match as many of these non-capturing groups as possible

)              - close the group, nothing is captured as there is no capturing pattern in it

" p            - followed by a literal string: `" p`

想像这样的字符串:name ="data.messageHeader.msg_time_tag.$date" pzb 。如果你在上面执行上面的模式,你会很容易地捕获你的 name ="data. 部分,这就是乐趣开始的时候 - 不要介意外部组,问题在于内部组和它后面的 + 限定符 -它将匹配第一个 messageHeader.,然后它会捕获 msg_time_tag. 等等,直到遇到引号字符...但是,由于 $date 不符合内部模式,它会移动回到 messageHeader. 的上一场比赛(回溯)并再次尝试 - 只是遇到同样的问题,并再次回溯......再次......再次......最终关闭引擎并导致非-可预测的行为。

正则表达式引擎将如何选择处理这个取决于实现 - 最合适的方法是引发 infinite/catastrophic 回溯错误(因为尽管有匹配和模式不提供解决方案),但它可能会因什么都不捕获或捕获所有而失败...

底线是 - 如果您编写正确的正则表达式模式,正则表达式引擎将按预期运行。如果没有 - 一切顺利。

正如 Wiktor 所说,正则表达式将导致灾难性的回溯。具体来说,它是可选的周期,在回溯时,将允许正则表达式尝试搜索字符串的指数排列。以下正则表达式通过强制内部单词后跟句点来防止灾难性回溯。

name ="\w+\.((\w+\.)*\w+)" p