【问题标题】:PHP crashes on preg_replacePHP 在 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 我的回答是否也让它崩溃了?

标签: php crash preg-match


【解决方案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】:

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-18
    • 2016-02-11
    • 1970-01-01
    • 1970-01-01
    • 2011-05-10
    • 2018-11-01
    • 1970-01-01
    • 2011-01-24
    相关资源
    最近更新 更多