我已经知道\w
在PCRE中(特别是PHP的实现)有时可以匹配一些非ASCII字符,具体取决于系统的语言环境,但是呢[a-z]
?
我不这么认为,但我注意到Drupal的核心文件之一中的这些行(包括/ theme.inc,简化):
// To avoid illegal characters in the class, // we're removing everything disallowed. We are not using 'a-z' as that might leave // in certain international characters (e.g. German umlauts). $body_classes[] = preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', $class);
这是真的吗,还是只是有人[a-z]
混淆了\w
?
长话短说:也许,取决于应用程序部署的系统,取决于PHP的编译方式,欢迎来到本地化和国际化的CF.
在确定"az"的含义时,底层PCRE引擎会考虑区域设置.在基于西班牙语的语言环境中,ñ将被az捕获.az的语义是"a和z之间的所有字母,而ñ是西班牙语中的单独字母.
但是,PHP盲目处理字符串作为字节集合而不是UTF代码点集合的方式意味着你有一种情况,即az MIGHT匹配重音字符.考虑到Drupal被部署到的不同系统的多样性,他们会选择明确允许的字符,而不是仅仅信任az来做正确的事情.
我还猜想这个正则表达式的存在是关于德语变音符号未被过滤的错误报告的结果.
2014年更新:根据JimmiTh的回答,看起来(尽管有一些"令人困惑的非核心开发人员"文档)[a-z]
只会在abcdefghijklmnopqrstuvwxyz
99%的时间内与人物相匹配.也就是说 - 框架开发人员往往会对代码中的模糊性感到不安,特别是当代码依赖于PHP无法正常处理的系统(特定于语言环境的字符串)时,以及开发人员无法控制的服务器.虽然匿名Drupal开发人员的评论不正确 - 这不是" [a-z]
混淆\w
"的问题,而是Drupal开发人员不清楚/不确定PCRE如何处理[a-z]
,并选择更具体的形式abcdefghijklmnopqrstuvwxyz
来确保他们想要的特定行为.
Drupal代码中的注释错误.
这是不是真的," international characters (e.g. German umlauts)
"可能匹配[a-z]
.
例如,如果您有德语区域设置,您可以这样检查:
setlocale(LC_ALL, 'de_DE'); // German locale (not needed, but you never know...)
echo preg_match('/^[a-z]+$/', 'abc') ? "yes\n" : "no\n";
echo preg_match('/^[a-z]+$/', "\xE4bc") ? "yes\n" : "no\n"; // äbc in ISO-8859-1
echo preg_match('/^[a-z]+$/', "\xC3\xA4bc") ? "yes\n" : "no\n"; // äbc in UTF-8
echo preg_match('/^[a-z]+$/u', "\xC3\xA4bc") ? "yes\n" : "no\n"; // w/ PCRE_UTF8
输出(如果替换de_DE
,则不会改变de_DE.UTF-8
):
yes
no
no
no
字符类[abcdefghijklmnopqrstuvwxyz]
与[a-z]
PCRE理解的两种编码相同:ASCII衍生的单字节和UTF-8(也是ASCII衍生的).在这两种编码中[a-z]
都是一样的[\x61-\x7A]
.
当问题在2009年被问到时,事情可能会有所不同,但在2014年,没有"奇怪的配置"可以使PHP的PCRE正则表达式引擎解释[a-z]
为超过26个字符的类(只要它[a-z]
本身写为5个字节)当然是ASCII派生的编码).
只是对已经很好的,如果相互矛盾的答案的补充.
PCRE库的文档始终声明"范围在字符值的整理顺序中运行".这有点模糊,但非常精确.
它指的是通过PCRE内部字符表中的字符索引进行整理,可以将其设置为与当前使用的语言环境匹配pcre_maketables
.该函数按char值(tolower(i)
/ toupper(i)
)的顺序构建表
换句话说,它不会按实际文化排序顺序(区域设置排序规则信息)进行整理.例如,虽然德语在字典整理中将o与o相同,但是ö的值使得它在用于德语的所有常用字符编码(ISO-8859-x,unicode编码等)中显示在az范围之外.在这种情况下,PCRE将确定ö是否在该[a-z]
代码值的范围内,而不是任何实际的语言环境定义的排序顺序.
PHP主要在他们的文档中逐字复制PCRE的文档.然而,他们实际上已经痛苦地将上述陈述改为"Ranges以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_maketables
- 在编译 PCRE时生成(由) - 基于编译器的语言环境:
此函数为小于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],即与代码顺序相关,而不是文化排序顺序.