PHP 在 preg_replace 上崩溃

Posted

技术标签:

【中文标题】PHP 在 preg_replace 上崩溃【英文标题】:PHP crashes on preg_replace 【发布时间】:2013-03-14 13:04:03 【问题描述】:

我使用php.exe 运行了以下脚本:

preg_replace('#(?:^[^\pL]*)|(?:[^\pL]*$)#u','',$string);

或其等价物:

preg_replace('#(?:^[^\pL]*|[^\pL]*$)#u','',$string);

如果$string="S"$string=" ذذ " 有效,如果string='ذ' 它产生 不正确,如果string='ذذ' PHP 崩溃。

但它适用于 4.4.0 - 4.4.9、5.0.5 - 5.1.6 版本。

怎么了?

:http://3v4l.org/T3rpV


<?php
$string='دد';
echo preg_replace('#(?:^[^\pL]*)|(?:[^\pL]*$)#u','',$string);

5.4.0 - 5.5.0alpha6 的输出

Process exited with code 139.

5.2.0 - 5.3.22、5.5.0beta1 的输出

 

4.4.0 - 4.4.9、5.0.5 - 5.1.6 的输出

دد 

4.3.11、5.0.0 - 5.0.4 的输出

Warning: preg_replace(): Compilation failed: PCRE does not support \L, \l, \N, \P, \p, \U, \u, or \X at offset 7 in /in/T3rpV on line 3 

4.3.0 - 4.3.10 的输出

Warning: Compilation failed: PCRE does not support \L, \l, \N, \P, \p, \U, \u, or \X at offset 7 in /in/T3rpV on line 3

【问题讨论】:

这里也崩溃了。 PHP 5.4.7。 我可以确认,最新的 beta 版本 PHP 5.5.0beta2(3 月 28 日发布)也会崩溃! @ComFreek 我的回答是否也让它崩溃了? 【参考方案1】:

您可以使用替代 mb_ereg_replace() 函数:

mb_internal_encoding("UTF-8");
mb_regex_encoding("UTF-8");
echo mb_ereg_replace('#(?:^[^\pL]*)|(?:[^\pL]*$)#u','',$string);

【讨论】:

不,你不能see it 你的正则表达式的行为完全不同,并不等同于我的。试试看:$string='.d.' RegEx 应该重新格式化为 POSIX 语法。另外我不确定它是否支持 POSIX \pL【参考方案2】:

也许这会有所帮助:

这些属性通常仅在 PCRE 编译时可用 "--enable-unicode-properties"

http://docs.php.net/manual/en/regexp.reference.unicode.php#96479

【讨论】:

如果这些属性不可用,PHP 会发出警告而不是崩溃。 根据我自己的经验,ive had a hard time when \b ( any word boundary character ) silently did not work with cyrillic symbols, it just ignored them, on the other hand, working as intended with latin. I had to use monster stuff like $boundL = '(^|[-\s\.>$boundR = '($|[-\s\.><,:;\!\?]+)';跨度> 【参考方案3】:

从表达式本身来看,有两点可以改进:

    * 乘数不是很有用;为什么要用空字符串替换可能为空的匹配项?事实上,在我的系统上运行它会从 preg_replace() 操作中产生 NULL

    内存组可以合并在一起。

这是应用两项改进后的代码:

$string = 'ﺫﺫ';
var_dump(preg_replace('#(?:^[^\pL]+|[^\pL]+$)#u', '', $string));
// string(4) "ﺫﺫ"

3v4l results

如果您只是在寻找多字节修剪功能(从 4.3.0 开始支持):

$string=' دد';
var_dump(preg_replace('#(?:^\s+|\s+$)#u', '', $string));

3v4l results

【讨论】:

“事实上,在我的系统上运行它会产生 NULL”哇!实际上你发现了另一个错误:3v4l.org/H1Ihk @PHPst 看起来像 :) 我的答案中的代码有帮助吗? @Jack 它不会崩溃,但会输出 string(6) "ﺫﺫ" 而不是您的预期结果。 @ComFreek 以字节为单位的长度并没有说太多,不知道为什么两个字符每个都需要 3 个字节。 @Phpst 我明白了。我会在 bugs.php.net 报告一个错误并参考这个问题。【参考方案4】:

使用preg_quote,您必须正确转义特殊字符,然后才能将其与您的正则表达式一起使用。例如:

<?php
$string = preg_quote("\دد");
echo preg_replace('#(?:^[^\pL]*)|(?:[^\pL]*$)#u','',$string);

查看实际操作:http://3v4l.org/LeBXg

更多关于preg_quote。

干杯,

阿迪

【讨论】:

preg_quote 引用正则表达式字符,对于普通字符不是必需的。甚至echo preg_replace('#(?:^[^\pL]*|[^\pL]*$)#u','',preg_quote('ذذ')); 崩溃。 preg_quote("\دد");\\ss,这是一个不同的字符串。 可能你误解了preg_quote()的目的,它是为了转义特殊字符以供inside正则表达式使用:) 别提了;至少我能为一位前同事做的,呵呵。 @Jack 请参考 php.net/manual/en/function.preg-quote.php 并重新阅读问题。谢谢。【参考方案5】:

终于解决了这个bug:

Output for 4.4.0 - 4.4.9, 5.0.5 - 5.1.6, 5.5.27 - 5.5.33, 5.6.11 - 7.0.4, hhvm-3.6.1 - 3.12.0
    دد

【讨论】:

以上是关于PHP 在 preg_replace 上崩溃的主要内容,如果未能解决你的问题,请参考以下文章

PHP7 preg_replace出错及解决办法

mysql内部的preg_replace不能在循环php之外打印[重复]

preg_replace 这个:123.. - 可能是一个简单的 PHP / preg_replace / RegEx 问题,但老实说我很难过

[PHP] PHP7已经删除了preg_replace的e修饰符

php preg_replace遇到替换本身有括号的内容怎么办

PHP:输出一行不带preg_replace的HTML文档