【问题标题】:re.search() and re.findall() are hangingre.search() 和 re.findall() 挂起
【发布时间】:2019-02-23 15:46:18
【问题描述】:

我在使用 re.search() 或 re.findall() 时遇到问题。但让我先解释一下。我正在搜索 C 代码,其中包含如下定义:

#define SOME_FUNCTION( someArgument, someMoreArgument)

有时,当它们有很多参数时,它们会被包装起来,所以它们看起来像这样:

#define ANOTHER_FUNCTION( moreArgument, evenMoreArguments,
                          anAwfulLotOfArguments, youGetIt)

现在我正在使用 python 扫描这些文件以找到其中的每一个定义。我的正则表达式如下所示:

#define [A-Z,_]*\((?:.|\s)+?\"

在像regex101.com 这样的测试引擎中使用单行和多行定义进行测试时,它可以完美运行。

但是,当我将它与 python (3.4.1) 一起使用时,它仅适用于单行定义。当它尝试扫描多行定义时,它只是停止执行(尽管我可以用 Ctrl + C 中断它)。我尝试使用:

regexFullMacro = re.compile("#define [A-Z,_]*\((?:.|\s)+?\)")
match = regexFullMacro.search(searchString)

还有

regexFullMacro = re.compile("#define [A-Z,_]*\((?:.|\s)+?\)")
match = regexFullMacro.findall(searchString)

当涉及多行时,两者都尝试停止响应。

以前有没有人遇到过这个问题,或者我只是完全愚蠢并且遗漏了一些明显的东西?

【问题讨论】:

  • 当您在 regex101 上进行测试时,您是否使用源文件的全部内容作为样本?您可能在回溯方面遇到问题,但如果您仅使用短字符串进行测试,这将不会引起注意...
  • 一个明显的事情是永远不要在正则表达式模式中使用(?:.|\s)+?。它会导致如此重的回溯,以至于引擎卡住了。您总是希望 . 带有 DOTALL 修饰符或 [\s\S] 在需要仅将此行为应用于模式的一部分时。在这种情况下,"#define [A-Z,_]*\([^()]+\)" 应该足够了,因为否定字符类 [^()] 匹配除 () 之外的任何字符,包括换行符。
  • @WiktorStribiżew 对。在那个地方改用[^)]+,这不会做任何回溯。
  • 感谢您的快速回复。我使用了@WiktorStribiżew 提供的解决方案,它完美无缺。如果我可以请您帮忙,您能否描述一下,[^()]+ 比 (?:.|\s)+ 做得更好的地方是什么?为什么该解决方案不会产生任何回溯?那太棒了

标签: python regex


【解决方案1】:

解决方案

r"#define [A-Z,_]*\([^()]+\)"

否定字符类[^()] 匹配除() 之外的任何字符(包括换行符),并且+ 量词使正则表达式引擎匹配它们的1 个或多个连续出现。

根本原因

正则表达式模式中的(?:.|\s)+?(当有其他子模式要遵循时)会导致过多的扩展操作(这是一种惰性模式,我们只能谈论使用贪婪修饰符的回溯),从而冻结正则表达式引擎。这个交替组的主要问题是. 可以匹配\s 匹配的内容。当一个组中的交替可以在同一位置匹配时,它总是一个瓶颈,因为一旦一个选择失败,另一个会被尝试,如果组被量化(如此处)继续尝试更多次。

您总是希望. 带有DOTALL 修饰符或[\s\S],而不是当需要仅将此行为应用于模式的一部分时(在Python re 中,[\S\s] workaround 非常有用,因为re does not support modifier groups)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-18
    • 2013-11-23
    • 1970-01-01
    • 2019-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多