【问题标题】:Pathological regex that blows up (time & memory)?爆炸的病态正则表达式(时间和记忆)?
【发布时间】:2011-07-15 11:53:57
【问题描述】:

什么是导致许多解析器(时间和内存)崩溃的病态正则表达式? 以及哪些解析器?正则表达式越基本和标准,非恶意用户就越有可能无辜地提出它。 随意发布实际时间和内存数据,以及解析器版本。

(我似乎记得 PERL 中的过度后向断言或 (EDIT:) 回溯据说会这样做,或者至少曾经是这样做的。还有其他的吗?)

【问题讨论】:

  • 你对回溯的想法,如果你能控制主题和模式,几乎任何基于 NFA 的正则表达式引擎都可以被欺骗成准无限回溯。基于 DFA 的引擎不需要进行回溯,因此它们不会遇到这种陷阱。下一个问题的答案是“因为 DFA 通常无法支持 NFA 可以提供的功能。”

标签: php python regex perl


【解决方案1】:

改编自文章Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby, ...)中的第一个例子:

perl -e '$n=29; ("a" x $n) =~ (("a?" x $n).("a" x $n))'

这在我的系统上需要 40 多秒。然后$n++ 以指数级增加乐趣...

【讨论】:

  • 奇怪的是,每个正则表达式引擎都没有对此进行优化。将a?a? 减少到a{,2} 非常基础,因此可以在课堂上教授。
  • 综合例子,但有用的文章,具有跨语言比较。
【解决方案2】:

来自 Russ Cox 的优秀 article$ perl -e '("a" x 100000) =~ /^(ab?)*$/;'。这显然会导致段错误。文章中还有更多内容。

【讨论】:

  • Python 和 GNU grep 对此没有任何问题。 re.match(r'^(ab?)*$', 'a'*10000000)
  • 这并没有导致我的 perl 5.10.1 安装出现问题,并且似乎在 5.8 codepad.org/hFlqUWk8 的键盘上运行良好
  • @Eric Strom:我认为作者是在针对 perl 5.8.7 进行测试。
  • @Glenn Maynard,GNU grep 是基于 DFA 的,在这个设置上它不会失败,因为这个示例针对的是基于 NFA 的引擎的一个常见弱点。
  • @ErikHaliewicz 你在我嘴里说的话。我并没有说所有 NFA 基础引擎在这些表达式上都失败了,只是说它很常见。您正确地认为问题是回溯,但我专门回答了为什么 GNU grep 没有失败。 GNU grep 使用 DFA,DFA 通常不会回溯,因为永远不会回溯到备用状态。
【解决方案3】:

我总是使用这个正则表达式来匹配 PHP 中的字符串或 PHP 中的 JavaScript 源代码:

~'(\\.|[^'])*'|"(\\.|[^"])*"~s

而且它几乎总是在很长的字符串上失败(大约 50000 个字符长就可以了)。

【讨论】:

  • 这使用 ~ 分隔符,因为它包含两种类型的引号;试图将其转换为 Python 正则表达式来测试它,但转义让我抓狂。任何人都可以转换它吗?
  • 我主要使用 this approach due to Tim Peters 转换它,除了 s 修饰符(点匹配每个字符?)...我怀疑这会让情况变得更糟。
  • This poster 提高了正则表达式的效率,看看吧!
猜你喜欢
  • 2012-03-28
  • 2015-01-21
  • 1970-01-01
  • 1970-01-01
  • 2020-07-18
  • 2021-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多