2009-12-18 39 views
17

我已经知道PCRE中的\w(特别是PHP的实现)有时可以匹配一些非ASCII字符,具体取决于系统的区域设置,但[a-z][a-z]是否会在PREG/PCRE中匹配重音字符?

我不这么认为,但我注意到在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

回答

13

长话短说:也许,取决于应用程序部署到的系统,取决于如何编译PHP,欢迎来到本地化和国际化的CF。

底层PCRE引擎在确定“a-z”的含义时考虑了区域设置。在西班牙语的语言环境中,ñ会被a-z抓住)。 AZ的语义是“所有A和Z之间的字母,N是西班牙一个单独的字母。

然而,PHP一味地处理字符串作为一个字节的集合,而不是UTF代码点集合的方式意味着你有一种情况,az可能匹配重音字符考虑到Drupal部署的各种不同系统,它们会选择明确允许的字符而不是仅仅信任az来做正确的事情。

我也猜想这个正则表达式的存在是由于德国变音器没有被过滤而引起的错误报告的结果。

更新在2014年:每JimmiTh's answer below,它看起来像(尽管有些“混乱到非PCRE核心开发人员”文档)是[a-z]将只匹配字符abcdefghijklmnopqrstuvwxyz时一个众所周知的99% 。这就是说 - 框架开发人员倾向于在代码中模糊不清,特别是当代码依赖于系统(特定于语言环境的字符串)时,PHP无法按照您的意愿优雅地处理,以及开发人员无法控制的服务器。尽管匿名的Drupal开发者的评论是不正确的 - 这不是“得到[a-z]\w混淆”的问题,而是一个Drupal开发者不清楚/不确定PCRE如何处理[a-z],并选择更具体的abcdefghijklmnopqrstuvwxyz形式来确保他们想要的具体行为。

+0

这是真的在2009年吗? – 2014-04-02 06:18:38

+0

@WalterTross今天仍然如此,真是如此。它从来不是关于什么是/是常见的,而是关于一些奇怪的配置会发生什么,并确保您的代码足够健壮以处理它。 – 2014-04-02 07:36:37

+1

@AlanStorm,你能提供这么奇怪的配置吗?我很确定没有! – 2014-04-02 08:30:03

10

The comment在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.UTF-8替换de_DE不会改变):

yes 
no 
no 
no 

的字符类[abcdefghijklmnopqrstuvwxyz]等同于[a-z]在这两种编码中,PCRE都能理解:ASCII派生的monobyte和UTF-8(也是ASCII派生的)。在这两种编码中,[a-z][\x61-\x7A]相同。

情况可能有所不同,当有人问在2009年,但在2014年没有“怪异配置”,可以使PHP的PCRE正则表达式引擎解释[a-z]作为一类超过26个字符(只要[a-z]本身当然是以ASCII码派生的编码写成5个字节)。

+1

你钉了它+1 – HamZa 2014-04-03 21:49:20

+0

当PHP文件的编码改变时会发生什么? – 2014-04-10 23:16:27

+0

@AlanStorm:只要编码是ISO-8859- *,UTF-8或包含英文小写字母的任何Windows代码页:无。另一方面,它看起来像PHP可以编译为了读取,例如,UTF-16源代码(我不知道这一点)。我没有精力去尝试。如果有人有,他们可以在这里发表他们的发现。 – 2014-04-11 12:29:20

7

除了已经很好的,如果矛盾的答案,只是一个补充。

PCRE库的文档一直声明“范围在字符值的整理顺序中运行”。这有点模糊,但非常精确。

它指的是通过在PCRE内部字符表的字符的索引,其可被设置以匹配使用pcre_maketables当前区域整理。该函数按照char值的顺序构建表(tolower(i)/toupper(i)

换句话说,它不按实际的文化排序顺序(区域设置排序规则信息)进行排序。例如,虽然德语在词典整理中将o与o相同,但ö的值使其在德语所使用的所有常用字符编码(ISO-8859-x,unicode编码等)中出现在z范围外。在这种情况下,PCRE将根据该代码值确定ö是否在[a-z]范围内,而不是任何实际的区域设置排序顺序。

PHP大多复制PCRE's documentation逐字在their docs。但是,他们实际上已经努力将上述语句更改为“范围在ASCII对齐序列中操作”。至少自2004年以来,这种说法一直在文档中。

尽管如此,但我不太确定它是否属实。嗯,至少在所有情况下都不是这样。

的一个调用PHP使得以pcre_maketables ...从PHP source

#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是我能想到的一种字符编码方式,它不会以不间断的顺序放置a-z和A-Z。

除非PCRE在使用EBCDIC(可能的话)时会有一些神奇的功能,尽管极其不可思议的是,除了最晦涩的PHP构建或运行时环境之外,您还会在其中包含变音器(使用您自己的,非常特殊的,您的可能,在EBCDIC的情况下,包括其他意想不到的字符。而对于其他范围,“按ASCII顺序整理”似乎并不完全准确。

ETA:我可以通过寻找菲利普·黑兹尔自己回答了类似的担忧已经存了一些研究:

另一个问题是与字符类范围。你会认为[a-k]和[x-z]对于拉丁脚本是很好的定义,但事实并非如此。

他们肯定明确的,等同于[\ x61- \ X6B]和[\ x78- \ X7A],也就是涉及到代码顺序,而不是文化的排序顺序。

+1

[pcre_maketables()](http://vcs.pcre.org/viewvc/code/trunk/pcre_maketables.c?view=markup)只生成以下表格:下方的表格,案例翻转表,字符类表,字符类型表。它不涉及整理。关于EBCDIC,如果有人向我展示一台实际运行PHP的EBCDIC机器,PHP中的PCRE将'[a-z]'解释为'[\ x81- \ xA9]',我就放弃了。 – 2014-04-06 22:33:27

+0

是的。因此“换句话说,它不会按照实际的文化排序顺序(区域设置整理信息)进行整理”。答案*的全部要点是*它不处理排序规则。 – JimmiTh 2014-04-06 22:40:23

+1

strcmp(3)的琐碎事情是,当字符串匹配时它返回false的等价物。所以,pcre_maketables被称为任何东西,但C语言环境。 – Melvyn 2014-04-09 06:42:05

相关问题