[a-z] 是否会匹配 PREG/PCRE 中的重音字符?

2022-08-30 23:15:33

我已经知道在PCRE(特别是PHP的实现)中,有时可以根据系统的区域设置匹配一些非ASCII字符,但是呢?\w[a-z]

我不这么认为,但我在Drupal的一个核心文件(include/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


答案 1

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

基础 PCRE 引擎在确定“a-z”的含义时会考虑区域设置。在基于西班牙语的区域设置中,ñ 将被 a-z 捕获)。a-z 的语义含义是“a 和 z 之间的所有字母,ñ 在西班牙语中是一个单独的字母。

但是,PHP 盲目地将字符串作为字节集合而不是 UTF 码位集合来处理的方式意味着 a-z 可能与重音字符匹配。考虑到Drupal部署到的各种不同系统,他们会选择明确允许的字符,而不仅仅是信任a-z做正确的事情是有道理的。

我还推测,这个正则表达式的存在是由于提交了关于德语元音变音符未被过滤的错误报告的结果。

2014年更新:根据Jimmith在下面的答案,看起来(尽管有一些“令人困惑的非pcre核心开发人员”文档)只能在99%的时间内与字符匹配。也就是说,框架开发人员往往会对代码中的模糊性感到抽搐,特别是当代码依赖于PHP无法像您希望的那样优雅地处理的系统(特定于区域设置的字符串)以及开发人员无法控制的服务器时。虽然匿名的Drupal开发人员的评论是不正确的 - 这不是一个“混淆”的问题,而是Drupal开发人员不清楚/不确定PCRE如何处理,并选择更具体的形式来确保他们想要的特定行为。[a-z]abcdefghijklmnopqrstuvwxyz[a-z]\w[a-z]abcdefghijklmnopqrstuvwxyz


答案 2

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_DEde_DE.UTF-8

yes
no
no
no

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

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


推荐