UTF-8模式正则表达式

时间:2016-06-06 12:58:12

标签: php regex utf-8 pcre character-class

问题

尽管PHP手册说明:

  

"In UTF-8 mode, characters with values greater than 128 do not match any of the POSIX character classes."

为什么波斯数字与“UTF-8模式”中的\d[[:digit:]]匹配?

精化

non-related question中的回答者的评论中提到,在正则表达式中,\d不仅匹配ASCII数字09,还包括,例如,波斯数字(۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷)。

上面提到的问题标记为,但行为也可以在PHP中观察到。考虑到这一点,我写了以下“测试”:

$string = 'I have ۳ apples and 5 oranges';
preg_match_all('/\d+/', $string, $capture);

结果数组$capture仅包含5 的匹配。

使用u修饰符启用“UTF-8模式”并运行此命令:

$string = 'I have ۳ apples and 5 oranges';
preg_match_all('/\d+/u', $string, $capture);

导致$capture包含۳5的匹配。

备注

  • 这个问题涉及PHP 5.6.22(迄今为止最新)
  • 两个测试都是在明确使用C区域设置时执行的。

1 个答案:

答案 0 :(得分:3)

因为文档被破坏了。不幸的是,它不是唯一一个如此的地方。

PHP使用PCRE来实现其preg_*功能。因此,PCRE的文档具有权威性。 PHP的文档基于PCRE,但看起来你发现了另一个错误。

以下是您在PCRE's docs(强调我的)中可以阅读的内容:

  

默认情况下,值大于128的字符与任何POSIX字符类都不匹配。但是,如果PCRE_UCP选项传递给pcre_compile(),则部分更改类以便使用Unicode字符属性。这是通过用其他序列替换某些POSIX类来实现的,如下所示:

[:alnum:]  becomes  \p{Xan}
[:alpha:]  becomes  \p{L}
[:blank:]  becomes  \h
[:digit:]  becomes  \p{Nd}
[:lower:]  becomes  \p{Ll}
[:space:]  becomes  \p{Xps}
[:upper:]  becomes  \p{Lu}
[:word:]   becomes  \p{Xwd}

如果你在PHP的文档中进一步挖掘,你会发现the following

  

u(PCRE_UTF8

     

此修饰符打开与Perl不兼容的PCRE的其他功能。模式和主题字符串被视为UTF-8。此修饰符可从Unix上的PHP 4.1.0或更高版本以及win32上的PHP 4.2.3获得。自PHP 4.3.5起,检查模式和主题的UTF-8有效性。无效主题将导致preg_*函数无匹配;无效模式将触发级别E_WARNING的错误。自PHP 5.3.4起,五个和六个八位字节UTF-8序列被视为无效(分别为PCRE 7.3 2007-08-28);以前那些被认为是有效的UTF-8。

不幸的是,这是谎言。 PHP中的u修饰符表示PCRE_UTF8 | PCRE_UCP(UCP代表Unicode字符属性)。正如您在上面的文档中所看到的,PCRE_UCP标志可以更改\d\w等的含义。您的测试证实了这一点。

作为旁注,不要从另一个推断出一种正则表达式的特性。它并不总是有效(嘿,甚至this chart忘记了PCRE_UCP选项。