LC_COLLATE 是否(应该)影响字符范围?

Gil*_*il' 27 regular-expression locale

Collat​​ion order throughLC_COLLATE不仅定义了单个字符的排序顺序,还定义了字符范围的含义。或者是吗?考虑以下片段:

unset LANGUAGE LC_ALL
echo B | LC_COLLATE=en_US grep '[a-z]'
Run Code Online (Sandbox Code Playgroud)

直观地说,B不是 in [a-z],所以这不应该输出任何东西。这就是 Ubuntu 8.04 或 10.04 上发生的事情。但是在一些运行 Debian lenny 或挤压的机器上,B可以找到,因为范围a-z包括排序顺序之间a和z排序顺序中的所有内容,包括大写字母B到Z.

所有测试的系统都en_US生成了语言环境。我还尝试改变语言环境:在B上面匹配的机器上,{en_{AU,CA,GB,IE,US},fr_FR,it_IT,es_ES,de_DE}{iso8859-1,iso8859-15,utf-8}除了日语(任何可用的编码)和C/之外的每个可用语言环境(主要基于拉丁语:,还有中文语言环境)都会发生同样的情况POSIX。

当您超越 ASCII 时,字符范围在正则表达式中意味着什么?为什么一方面某些 Debian 安装与其他 Debian 安装和 Ubuntu 之间存在差异?其他系统的行为如何?谁是对的,谁应该报告错误?

(请注意,我特别询问字符范围的行为,例如[a-z]在en_US语言环境中,主要是在基于 GNU libc 的系统上。我不是在询问如何匹配小写字母或 ASCII 小写字母。)


在两台 Debian 机器上,一台B在[a-z],一台不在,输出LC_COLLATE=en_US locale -k LC_COLLATE是

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=1
collate-codeset="ISO-8859-1"
Run Code Online (Sandbox Code Playgroud)

和输出LC_COLLATE=en_US.utf8 locale -k LC_COLLATE是

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2039
collate-codeset="UTF-8"
Run Code Online (Sandbox Code Playgroud)

Nei*_*hew 5

如果您使用除C区域设置之外的任何内容,则不应使用类似的范围[a-z],因为这些范围取决于区域设置,并且并不总是给出您期望的结果。除了您已经遇到的大小写问题外,某些语言环境将带变音符号的字符(例如\xc3\xa1 )视为与基本字符(即a )相同。

\n\n

相反,使用命名字符类:

\n\n
\n
echo B | grep '[[:lower:]]'\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

这将始终给出区域设置的正确结果。但是,您需要选择区域设置以反映输入文本和您尝试应用的测试的含义。

\n\n

例如,如果您需要查找特定字节值,请使用C始终可用的区域设置:

\n\n
\n
echo B | LANG=C grep '[a-z]'\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

如果这没有按预期工作,那么它确实是一个错误。

\n

  • 我的观点是,显式范围的含义取决于区域设置,并且不同的系统不需要以相同的方式定义其区域设置,因此这不是一个错误。从技术上讲,您正在滥用系统,因此您不应该对出现“未定义”行为感到惊讶。另外,有几个人评论说他们无法在 Debian 系统上重现该行为,因此您的系统似乎存在一些异常情况。 (2认同)