PHP Preg 引擎中的错误:查找 Unicode 问题


Bug in PHP Preg engine: look-around Unicode issue

为什么遵循js代码字:

"آرد@".replace(/(?=.)/g,'!'); // returns: ""!آ!ر!د""

但是它的 php 等价物返回'!�!�!�!�!�!�'

preg_replace('/(?=.)/u', '!', 'آرد'); //returns '!�!�!�!�!�!�'

这仅适用于 4.3.5 - 5.0.5、5.1.1 - 5.1.6 版本。

请参阅: http://3v4l.org/jrV0W

如果只是添加 /u 修饰符,则该模式应被视为utf-8 。第二个示例之所以有效,是因为:

  1. 从 PHP 5.1 开始,您可以使用可以翻译为:"是来自任何语言的任何类型的字母"的'p{L}
  2. 除了标准的符号之外,''p{L},Java,Perl,PCRE和现在的PHP允许您使用速记'pL。速记仅适用于单字母 Unicode 属性。

更新:为什么preg_replace('/(?=.)/u', '!', 'آرد'); //returns '!�!�!�!�!�!�'??

正如@MarkFox所说,原因是因为在preg_replace()上下文中,它假设每个字符一个字节,而您"RegExing"的字符是多字节的。这就是为什么你的替换输出的匹配是你期望的两倍,它匹配每个字符的每个字节(我推断是两个字节(-

无论您对文档编码执行什么操作,都需要使用 Unicode 字符属性来使其正常工作。

那个奇怪的符号呢?

当您看到"里面有一个问号的奇怪方形符号"也称为替换字符时,这通常表明您的字节在 80-FF (128-255( 范围内,并且系统正在尝试以 UTF-8 呈现它。

整个字节范围对于UTF-8中的单字节字符是无效的,但在西方编码中(如ISO-8859-1(中都很常见。

现在测试了一些字符串后,我认为 PREG 引擎中存在错误。前三行输出预期,但第四行有故障。

<?php
echo preg_replace('/./'       , '#', 'آرد')   . PHP_EOL; //✓
echo preg_replace('/./u'      , '#', 'آرد')   . PHP_EOL; //✓
echo preg_replace('/(?=.)/'   , '#', 'آرد')   . PHP_EOL; //✓
echo preg_replace('/(?=.)/u'  , '#', 'آرد')   . PHP_EOL; //✗
echo preg_replace('/(?='pL)/' , '#', 'آرد')   . PHP_EOL; //?
echo preg_replace('/(?='pL)/u', '#', 'آرد')   . PHP_EOL; //?

输出:

######
###
#�#�#�#�#�#�
#�#�#�#�#�#�
#آ#ر#د
#آ#ر#د