PHP在preg_replace时崩溃

20
我使用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);

Output for 5.4.0 - 5.5.0alpha6

Process exited with code 139.

Output for 5.2.0 - 5.3.22, 5.5.0beta1

 

Output for 4.4.0 - 4.4.9, 5.0.5 - 5.1.6

دد 

Output for 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 

Output for 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

2
这里也会崩溃。PHP 5.4.7。 - Sverri M. Olsen
我可以确认,最新的beta版本PHP 5.5.0beta2(于3月28日发布)也会崩溃! - ComFreek
@ComFreek 我的回答也会导致它崩溃吗? - Ja͢ck
5个回答

5
您可以使用替代的mb_ereg_replace()函数:
mb_internal_encoding("UTF-8");
mb_regex_encoding("UTF-8");
echo mb_ereg_replace('#(?:^[^\pL]*)|(?:[^\pL]*$)#u','',$string);

不,它不是你可以看到的 - user1646111
你的正则表达式完全不同,而且与我的并不等价。请尝试:$string='.d.' - Handsome Nerd
1
正则表达式应该被重新格式化为POSIX语法。另外,我不确定它是否支持\pL - Handsome Nerd

3

1
如果这些属性不可用,PHP将发出警告而不是崩溃。 - Ja͢ck
从我的经验来看,当\b(任何单词边界字符)与西里尔字母一起使用时,它会默默地不起作用,只是忽略它们,但与拉丁字母一起使用时则正常工作。我不得不使用像下面这样的怪物代码:$boundL = '(^|[-\s\.><,:;\!\?]+)';$boundR = '($|[-\s\.><,:;\!\?]+)'; - Alex QLerR

1

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

  1. * 乘法因子并不是很有用; 为什么要用空字符串替换可能为空的匹配?实际上,在我的系统上运行此操作会从 preg_replace() 操作中返回 NULL

  2. 内存组可以合并在一起。

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

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

3v4l结果

如果你只是想要一个多字节的trim函数(从4.3.0版本开始支持):

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

3v4l结果


事实上,在我的系统上运行这个程序会返回 NULL。哇!你实际上发现了另一个 bug:http://3v4l.org/H1Ihk - Handsome Nerd
看起来是的 :) 不过我回答中的代码有帮到你吗? - Ja͢ck
@Jack 它没有崩溃,但输出的是 string(6) "ﺫﺫ" 而不是你期望的结果。 - ComFreek
@ComFreek,字节长度并不能说明太多问题,我不确定为什么每个字符都要占用3个字节。 - Ja͢ck
@Phpst 我明白了。我会在 bugs.php.net 上报告一个 bug,并提到这个问题。 - Ja͢ck

0

使用preg_quote函数,您必须在将其与正则表达式一起使用之前正确转义特殊字符。例如:

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

看它如何运作:http://3v4l.org/LeBXg

更多关于 preg_quote 的内容。

祝好,

Ardy


preg_quote是用于引用正则表达式字符的功能,对于普通字符来说是不必要的。但是即使 echo preg_replace('#(?:^[^\pL]*|[^\pL]*$)#u','',preg_quote('ذذ')); 也会崩溃。preg_quote("\دد"); 的结果是 \\ss,这是一个不同的字符串。 - Handsome Nerd
也许你误解了 preg_quote() 的目的,它是用来转义正则表达式内部的特殊字符的 :) - Ja͢ck
1
不用客气,这是我能为前同事做的最少的事情,呵呵。 - Ja͢ck
@Jack 请参考php.net/manual/en/function.preg-quote.php并重新阅读问题。谢谢。 - Handsome Nerd

0
最后,漏洞已解决:

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
    دد

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接