如何匹配/ \ s * a \ s * b /等正则表达式而不会过度回溯?

时间:2016-11-25 18:57:57

标签: regex perl backtracking

我在Perl工作,它使用回溯正则表达式引擎。

我需要匹配以空格分隔的标记的字符串(我正在解析汇编程序,以防有人想知道)。我目前正在使用像

这样的正则表达式
s/(\.text\n\s*\.align .(?:,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/$1/m

这样做,但我担心过度回溯。

我该如何防止这种情况?

3 个答案:

答案 0 :(得分:1)

一般方法是针对任何可能要进行回溯的子表达式,使用(?>...)包围子表达式。 例如,\s+将为(?>\s+)

答案 1 :(得分:0)

根据我的经验,很多人都试图在not required的地方使用正则表达式,很多人都试图避免它们where they're the best solution。所以我必须始终问 - 你想做什么?

对我来说,你要试图拆分一些代码。或许更容易扭转它,并且总是把它拉开然后将它作为制作过程的一部分组合起来?对于这种类型的东西,我经常会使用模板让我以正确的方式构建代码,并在此构建单元的特定代码中进行插值。然后我完全避免了正则表达式问题,这意味着我也可以避免开发人员做了一些我从未想到的事情。“/ p>

答案 2 :(得分:0)

老实说,该代码应该很少回溯。整个事情由.text锚定,其他可能发生回溯的地方将很快中止。不过,您可以尝试进行优化。

  • 使用\K删除了捕获(减慢速度)的需要。鉴于我上面所说的,这可能是提供最大利益的优化。
  • \s*替换为\s*+又名(?>\s*)(防止回溯,这是安全的,因为下一个字符不能是空格)。
  • 将最终.*替换为.*+又称(?>.*)(防止回溯,这是安全的,因为下一个字符不能是非换行符。)
  • (?:,0x90)?替换为(?:,0x90)?+(防止回溯,这是安全的,因为下一个字符不能是逗号)。
  • \s+.*_?替换为更简单但等效的\s.*

s/
    \.text \n
    \s*+
    \.align [ ] .(?:,0x90)?+ \n
    \K
    \.globl \s .* __stg_split_marker .*+ \n
//xm