3

问题

尽管 PHP 手册指出:

“在 UTF-8 模式下,值大于 128 的字符与任何 POSIX 字符类都不匹配。”

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

细化

在一个不相关问题的回答者评论中提到,在正则表达式中,\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语言环境时执行的。
4

1 回答 1

3

因为文档坏了。不幸的是,这不是唯一的地方。

PHP 在底层使用PCRE来实现其preg_*功能。因此,PCRE 的文档在那里具有权威性。PHP 的文档是基于 PCRE 的,但您似乎发现了另一个错误。

以下是您可以在PCRE 的文档中阅读的内容(重点是我的):

默认情况下,值大于 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 的文档,您会发现以下内容

你 ( PCRE_UTF8)

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

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


作为旁注,不要从另一种正则表达式风格中推断出一种正则表达式风格的属性。它并不总是有效(嘿,即使这张图表也忘记了这个PCRE_UCP选项)。

于 2016-06-06T20:26:58.853 回答