【问题标题】:Regex expression stops working in PHP 7.3正则表达式在 PHP 7.3 中停止工作
【发布时间】:2019-06-14 15:48:54
【问题描述】:

我有一个递归正则表达式来获取括号 [] 之间的文本:

    preg_match_all("#\[(([^\[\]]*|(?R))*)\]#", $string, $matches);

它工作正常,我一直在 PHP 5.6 和 7.0 中使用它,没有任何问题。 我已将服务器升级到 PHP 7.3,但它停止处理长文本(超过 500,000 个字符)。

对于包含方括号的长文本,表达式返回 PHP 5.6 和 7.0 的所有结果,这是它应该的。

在 PHP 7.3 中,它返回一个空的 $matches 数组而不发送任何错误或警告消息。

我不知道为什么会这样。在我所有版本的 PHP 中,PCRE 的配置都相同。该问题仅出现在长文本中。我在 PHP 迁移指南中找不到任何提及该问题的内容。

【问题讨论】:

  • 您能找到一种方法来最小化失败的文本,或者将其作为链接完整提供吗?使用正则表达式,由您决定什么“有效”和无效。如果没有关于它应该和不应该匹配的内容以及失败的地方的指南和示例,这里几乎是猜测。
  • 我知道您可能会增加 JIT 编译器堆栈限制,但您仍然会遇到低效且缓慢的正则表达式。如果您使用正确的模式,则该限制可能不需要更新,请尝试"#\[([^][]*(?:(?R)[^][]*)*)]#"。检查this demo。或者,"#\[((?:[^][]++|(?R))*)]#" 也不错。
  • @Wiktor 你的回答给出了最好的结果。您建议的正则表达式适用于所有文本,除了一个仍然抵抗的很长的文本。请将您的评论转化为答案,以便我将其标记为已接受的答案。

标签: php regex


【解决方案1】:

您可以做两件事:增加 JIT compiler stack limit 和 2) 重写正则表达式以遵循 unroll-the-loop principle

图案看起来像

$regex = "#\[([^][]*(?:(?R)[^][]*)*)]#";

这样匹配:

  • \[ - 一个左括号
  • ([^][]*(?:(?R)[^][]*)*) - 捕获组匹配
    • [^][]* - 除方括号外的零个或多个字符
    • (?:(?R)[^][]*)* - 整个正则表达式模式 ((?R)) 的零个或多个重复,后跟零个或多个除方括号外的字符
  • ] - 右括号。​​

请参阅regex demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-29
    • 2014-02-22
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多