【问题标题】:Non-ASCII characters in UTF-8 mode regular expressionUTF-8 模式正则表达式中的非 ASCII 字符
【发布时间】:2016-10-06 02:28:37
【问题描述】:

问题

尽管 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 语言环境时执行的。

【问题讨论】:

  • 第一个没有u标志的测试当你的字符串不是ASCII时是没有意义的,因为匹配将使用字节语义进行。如果您将\wSHIFT-JIS 编码字符串一起使用,您可能会匹配某个字符的第二个字节。有关非 UTF 模式和后果的说明,请参阅此答案中的示例部分:stackoverflow.com/questions/20954580/maximum-hex-value-in-regex/…

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


【解决方案1】:

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

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

你 (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 (resp. PCRE 7.3 2007-08-28) 起,五个和六个八位字节的 UTF-8 序列被视为无效;以前那些被认为是有效的 UTF-8。

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


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

【讨论】:

  • 感谢卢卡斯的详尽回答。使用此信息,我提交了documentation bug report。让我们看看它是否被压扁,或者,确实,被纠正了。
猜你喜欢
  • 2016-10-02
  • 2013-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-30
  • 2012-04-09
  • 2011-01-08
  • 2012-11-21
相关资源
最近更新 更多