只是对已经很出色但自相矛盾的答案的补充。
PCRE 库的文档始终声明“范围在字符值的整理序列中运行”。这有点模糊,但非常精确。
它是指通过PCRE内部字符表中的字符索引进行排序,可以设置为匹配当前的语言环境使用pcre_maketables
。tolower(i)
该函数按 char 值 ( / toupper(i)
)的顺序构建表
换句话说,它不按实际的文化排序顺序(语言环境排序信息)进行排序。例如,虽然德语在字典排序中将 ö 与 o 视为相同,但 ö 的值使其在用于德语的所有常见字符编码(ISO-8859-x、unicode 编码等)中出现在 az 范围之外。在这种情况下,PCRE 将确定 ö 是否在[a-z]
该代码值的范围内,而不是任何实际的语言环境定义的排序顺序。
PHP在他们的 docs中大部分是逐字复制PCRE 的文档。然而,他们实际上已经煞费苦心地将上述语句更改为“范围以 ASCII 整理顺序运行”。至少自 2004 年以来,该声明一直在文档中。
尽管有上述情况,但我不太确定这是真的。
好吧,至少不是在所有情况下。
PHP 发出的一个调用pcre_maketables
...来自PHP 源代码:
#if HAVE_SETLOCALE
if (strcmp(locale, "C"))
tables = pcre_maketables();
#endif
换句话说,如果编译 PHP 的环境具有setlocale
并且(LC_CTYPE) 语言环境不是 POSIX/C 语言环境,则使用运行时环境的 POSIX/C 语言环境的字符顺序。否则,将使用默认的 PCRE 表 - 在编译 PCRE 时(由pcre_maketables
)生成 -基于编译器的 locale:
此函数为小于 256 的字符值构建一组字符表。这些可以传递给 pcre_compile() 以覆盖 PCRE 的内部内置表(在编译 PCRE 时由 pcre_maketables() 创建)。如果您使用的是非标准语言环境,您可能需要这样做。该函数产生一个指向表的指针。
虽然德语在任何常见的字符编码中都不会有所不同[a-z]
,但如果我们处理 EBCDIC,例如,[a-z]
将包括 ± 和 ~。当然,EBCDIC 是我能想到的一种字符编码,它不会将 az 和 AZ 置于不间断的序列中。
除非 PCRE 在使用 EBCDIC 时有一些魔力(它可能会),但除了最晦涩的 PHP 构建或运行时环境(使用您自己的、非常特殊的、定制的语言环境定义)之外,您极不可能在任何东西中包含变音符号,对于 EBCDIC,您可能会包含其他意外字符。而对于其他范围,“按 ASCII 序列排序”似乎并不完全准确。
ETA:我可以通过寻找 Philip Hazel 自己对类似问题的回复来节省一些研究:
另一个问题是字符类范围。您可能会认为 [ak] 和 [xz] 对拉丁脚本的定义很明确,但事实并非如此。
它们当然定义明确,相当于 [\x61-\x6b] 和 [\x78-\x7a],即与代码顺序有关,与文化排序顺序无关。