使用带有字符范围的 tr 命令

使用带有字符范围的 tr 命令

在过去的几个月里,我一直在 William E. Shotts 的帮助下学习命令行Linux 命令行Linux 命令行对于想要了解更多 Linux 命令行的新手来说,这本书仍然是一本受欢迎的书。

其中一章介绍了该tr命令。书中说,字符集可以用以下三种方式之一构建:枚举列表,例如ABCDEFGHIJKLMNOPQRSTUVWXYZ;字符范围,例如A-Z;以及 POSIX 字符类,例如[:upper:]

我不明白的部分是,书中告诉读者要谨慎使用字符集的字符范围,因为区域设置的排序顺序,并建议读者改用 POSIX 字符类。

我个人从未遇到过使用字符范围的问题,A-Z例如

echo "lowercase letters" | tr a-z A-Z

那么为什么我应避免使用字符范围而使用 POSIX 字符类呢?

如果你想知道,我的语言环境是 en_US.UTF-8。

答案1

您使用的是 UTF-8。耶!ASCII 以及 UTF-8(因为 UTF 人员试图使其成为 ASCII 的超集)的字母按字母顺序排列,没有间隙,因此a-z包含所有常规小写字符,而不包含其他任何内容,依此类推。

然而,在其他编码上,情况不一定如此。经典的例子是EBCDIC

字母之间的间隙使得在 ASCII 中有效的简单代码在 EBCDIC 中失效。例如,在 ASCII 字母表中for (c='A';c<='Z';++c)会设置c为 26 个字母,但在 EBCDIC 中会设置为 40 个字符(包括许多未分配的字符)。解决这个问题需要使用函数调用使代码复杂化,这遭到了程序员的强烈抵制。

我想没有人再使用这种奇怪的东西了,但是谁知道呢?


据我所知,GNU tr 不支持 Unicode,但对于支持的程序,[[:upper:]]也会匹配被视为大写字母的 Unicode 字符,例如全角“A”或带重音符号的 A:À。

$ printf "%s\n" A a A À | grep '[[:upper:]]'
A
À
$ printf "%s\n" A a A À | grep '[A-Z]'   # I'm also using Unicode, so grep tries to be friendly
A
À
$ printf "%s\n" A a A À | LC_ALL=C grep '[A-Z]'
A 

相关内容