【问题标题】:PHP 7 preg_replace PREG_JIT_STACKLIMIT_ERROR with simple stringPHP 7 preg_replace PREG_JIT_STACKLIMIT_ERROR 用简单的字符串
【发布时间】:2017-06-27 11:17:09
【问题描述】:

我知道其他人已经提交了有关此错误的问题,但是我看不出这个正则表达式或主题字符串如何更简单。

对我来说这是一个错误,但在将其提交给 PHP 之前,我想我会确保并获得帮助,看看这是否可以更简单。

这是一个显示 2 个字符串的小测试脚本;一个有 1024 x,一个有 1023:

// 1024 x's
$str = '_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; 

// Outputs nothing (bug?)
echo preg_replace('/(?<=[^\w]|^)_([^_\n\t ](.|\n(?!\n))*?)_(?=[^\w]|$)/', '[i]${1}[/i]', $str); 

echo "\n\n";

// 1023 x's
$str = '_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; 

// Outputs the unchanged string as expected
echo preg_replace('/(?<=[^\w]|^)_([^_\n\t ](.|\n(?!\n))*?)_(?=[^\w]|$)/', '[i]${1}[/i]', $str);

如您所见,只有稍长的字符串(大于 1024 个字符)才会出现错误。它将被处理的字符串将是任意长度——它们将是论坛帖子、新闻文章等。

正则表达式解释

只是尝试进行一些降价解析,将_I am italic_ 之类的字符串转换为我们在某些情况下从旧网站使用的旧版标记。原因/用途并不重要。重要的是,我相信这应该可以正常工作,事实上,除了 PHP 7 之外的其他任何地方都可以。

只有当它代表一个独立的单词或句子时,它才应该匹配这些下划线。如果它前面有任何基于“word”的字符,则不应匹配第一个下划线,如果后跟任何基于“word”的字符,则不应匹配最后一个下划线。

环境: Centos 7,PHP:7.1.6

【问题讨论】:

  • (.|\n(?!\n))*? 正在杀人。您可能想改用.*(?:\R(?!\R).*)*
  • 顺便说一句,here,PHP 7.1.0,两个字符串都显示了。
  • 这里不仅在 PHP 7.0.0 到 7.0.5 上显示。这似乎是一个错误3v4l.org/DfHDJ
  • @WiktorStribiżew 您的建议有效!我只需要在第一个星号之后添加一个问号即可消除贪婪。不知道为什么它在你的链接上工作。它绝对不适用于我的环境。

标签: php regex preg-replace pcre php-7


【解决方案1】:

重要提示
应避免使用 (.|\n)*?(.|\r?\n)*? 模式,因为它们会导致过多的冗余回溯。要匹配任何字符,您通常可以使用带有 DOTALL 标志的 .,或者,在 JavaScript 中,您可以使用 [^][\s\S] 构造。详情请见How do I match any character across multiple lines in a regular expression?

当前问题

(.|\n(?!\n))*? 模式效率非常低,并且当不在模式末尾使用时会导致大量冗余回溯(它根本没有意义)。越位于模式的左侧,性能越差。

由于它所做的只是匹配除换行符之外的任何字符,然后匹配一个不跟随另一个换行符的换行符,以一种懒惰的方式,您可以将模式重写为.*?(?:\R(?!\R).*?)*

'~\b_([^_\n\t ].*?(?:\R(?!\R).*?)*)_\b~'

请参阅regex demo

注意:

  • (?&lt;=[^\w]|^) = \b 因为后面有一个_(一个字字符)
  • (?=[^\w]|$) = \b 因为在前瞻之前有一个_
  • .*?(?:\R(?!\R).*?)* - 匹配:
    • .*? - 除换行符以外的任何 0+ 字符,尽可能少,然后
    • (?:\R(?!\R).*?)* - 零个或多个序列:
      • \R(?!\R) - 一个换行序列后面没有另一个换行序列(\R = \n\r\n\r
      • .*? - 除换行符以外的任何 0+ 字符,尽可能少

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-16
    • 1970-01-01
    • 2016-05-10
    相关资源
    最近更新 更多