"正则表达式太大" PHP

时间:2015-07-01 22:37:10

标签: php regex

我正在研究一个相对复杂,非常大的正则表达式。它目前有41,127个字符,并且可能会增加一些,因为可能会添加其他案例。我开始在PHP中出现此错误:

  

preg_match_all():编译失败:偏移41123处的正则表达式太大

有没有办法增加大小限制?其他地方建议的以下设置不起作用,因为这些适用于数据大小而不是正则表达式大小:

ini_set("pcre.backtrack_limit", "100000000");
ini_set("pcre.recursion_limit", "100000000");

或者,有没有办法定义一个"子模式变量"正则表达式中的正则表达式可以在正则表达式中的各个地方重复吗? (我不是在谈论使用*+重复,甚至不是重复匹配" 1")?我实际上使用的PHP变量包含在正则表达式中的几个地方重复的子模式,但是这会导致正则表达式在传递给PRCE函数之前扩展。

这是一个复杂的正则表达式,不能被更简单的关键字搜索替换为使用strposthis link建议的相似内容。

我宁愿避免将其拆分为| 的子表达式,并尝试分别匹配子表达式,因为缩小尺寸会适度(只有2个)或顶级|中的3个),这将使进一步的发展复杂化。

3 个答案:

答案 0 :(得分:6)

我不同意可能有更好方法的评论,但我会在这里回答这个问题。

您可以增加正则表达式的最大大小,但只能通过自己重新编译PHP。因此,您的代码根本不可移植,如果您使用的是预编译的二进制文件,那么您运气不佳。

那就是说,我建议找一个匹配的替代方案。

请参阅pcre_internal.h以获取评论。

  

PCRE将其编译代码中的偏移量保持为2字节数量   (默认情况下,始终以big-endian顺序存储)。这些用于   例如,从子模式的开头到其替代方案的链接   并结束。每个偏移使用2个字节限制了大小   编译正则表达式大约64K,几乎足够大   每一个人。但是,我收到了更大限制的请求。   出于这个原因,还要使代码更容易维护   现在处理从字节串中存储和加载偏移量   通过这里定义的宏。

     

宏是   由LINK_SIZE的值控制。默认为2   config.h文件,但可以在命令行上使用-D覆盖。   这是通过" configure"在Unix系统上实现的。命令。

因此,您可以从PHP源代码分发中编辑ext/pcre/pcrelib/config.h以增加大小限制,或在编译./configure -DLINK_SIZE=4

时指定它

编辑:如果您正在尝试匹配/解析HTML,我建议使用DOMDocument来解析HTML,然后遍历DOM树或构建XPATH以查找您正在寻找的内容。< / p>

答案 1 :(得分:6)

根据具体应用,有效的解决方案是:

  • 使用DEFINE缩短正则表达式用于任何冗余子表达式(见下文)。
  • 通过重新编译PHP来增加正则表达式大小的最大限制(请参阅drew010&#39;答案很棒)。虽然这可能并非在所有环境中都可用,但如果更改服务器可能会产生兼容性问题。
  • | 拆分正则表达式,并分别处理生成的子表达式。如果正则表达式基本上是由|分隔的众多关键字,那么使用strpos转换为strtok或循环可能是更好的&amp;更快的选择。
  • 使用其他语言/正则表达式引擎,例如C ++ / Boost ,虽然我没有验证这一点。

解决我的具体问题:根据Mario的评论,使用(?(DEFINE)...)构造对多次重复使用的某些子表达式减少了我的正则表达式大小从41,127个字符到#34;仅#34; 4,071,这是摆脱错误“正则表达式太大”的优雅解决方案。

请参阅: (?(DEFINE)...) syntax reference at rexegg.com

答案 2 :(得分:1)

让您尝试过的array_chunk拆分数组,然后在foreach()中使用preg_match_all。我使用的是完全相同的代码,并且我有一个40k +的数组,因此我通过了上述解决方案,但是它没有解决我的“编译失败:正则表达式在偏移处太大”的问题,然后将40k +数组拆分为4 1k个元素的数组,在我的preg_match_all条件下使用foreach(),瞧!有效。