unicode 字符的 tr 模拟?

fed*_*man 9 utilities unicode tr

我需要国际化的实用程序,它的作用与tr:从流中获取字符并将其替换为相应的字符。不是像从低到高这样的特定案例解决方案,而是需要通用案例解决方案。sed如果可能的话,不要使用 gorillion 管道电话。

请注意,这tr不适用于 Linux:它转换字节,而不是字符。这对多字节编码失败。

$ tr --version | head -n 1
tr (GNU coreutils) 8.23
$ echo $LC_CTYPE
en_US.UTF-8
$ echo 'Ångstrom' | tr Æ Œ         
?ngstrom
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 12

GNUsed可以处理多字节字符。所以:

$ echo 齯 | sed 'y/齯/ABŒ/'
ABŒ
Run Code Online (Sandbox Code Playgroud)

并不是说 GNUtr没有国际化,而是它不支持多字节字符(如 UTF-8 语言环境中的非 ASCII 字符)。GNUtr可以使用ÆŒ只要它们像 iso8859-15 字符集中一样是单字节的。

更多关于如何让 tr 知道非 ascii(unicode) 字符?

无论如何,这与Linux无关,而是关于tr系统上的实现。该系统是使用 Linux 作为内核还是tr为 Linux 构建或使用 Linux 内核 API 都无关紧要,因为这部分tr功能发生在用户空间中。

busyboxtr和 GNUtr在为 Linux 构建的软件发行版中最常见,并且不支持多字节字符,但还有其他一些已移植到 Linux 中,例如tr传家宝工具箱(从 OpenSolaris 移植)或 ast-打开那个做。

请注意,sed'sy不支持像a-z. 另请注意,如果包含的脚本sed 'y/齯/ABŒ/'是用 UTF-8 字符集编写的,如果在 UTF-8 不是字符集的区域设置中调用,它将不再按预期工作。

另一种方法是使用perl

perl -Mopen=locale -Mutf8 -pe 'y/a-z齯/A-ZABŒ/'
Run Code Online (Sandbox Code Playgroud)

上面,perl 代码预计为 UTF-8,但它将处理区域设置编码的输入(并以相同的编码输出)。如果在 UTF-8 语言环境中调用,它会将 UTF-8 Æ(0xc3 0x86)音译为 UTF -8 Œ(0xc5 0x92),并在 ISO8859-15 中音译为 0xc6 -> 0xbc。

在大多数 shell 中,即使脚本是在 UTF-8 不是字符集的语言环境中调用的,在单引号内包含这些 UTF-8 字符也应该没问题(一个例外是yash,如果这些字节不能形成有效字符,则会报错在语言环境中)。但是,如果您使用单引号以外的其他引用,则可能会导致问题。例如,

perl -Mopen=locale -Mutf8 -pe "y/?\`/&'/"
Run Code Online (Sandbox Code Playgroud)

在字符集为 BIG5-HKSCS 的区域设置中会失败,因为\(0x5c)的编码也恰好包含在其他一些字符中(例如?:0xa3 0x5c,并且 UTF-8 编码?恰好以 0xa3 结尾)。

无论如何,不​​要指望像

perl -Mopen=locale -Mutf8 -pe 'y/Á-?/A-Z/'
Run Code Online (Sandbox Code Playgroud)

致力于消除尖锐的口音。以上其实只是

perl -Mopen=locale -Mutf8 -pe 'y/\x{c1}-\x{179}/\x{41}-\x{5a}/'
Run Code Online (Sandbox Code Playgroud)

也就是说,范围基于 unicode 代码点。因此,在 Unicode中碰巧处于“正确”顺序的非常明确的序列之外,范围将没有用处,例如A-Z, 0-9

如果要删除重音符号,则必须使用更高级的工具,例如:

perl -Mopen=locale -MUnicode::Normalize -pe '
  $_ = NFKD($_); s/\x{301}//g; $_ = NFKC($_)'
Run Code Online (Sandbox Code Playgroud)

那就是使用 Unicode 规范化形式来分解字符,去除重音符号(这里是组合形式U+0301)并重新组合。

另一个用于音译 Unicode 的有用工具uconv来自ICU。例如,上面的也可以写成:

uconv -x '::NFKD; \u0301>; ::NFKC;'
Run Code Online (Sandbox Code Playgroud)

虽然只适用于 UTF-8 数据。你需要:

iconv -t utf-8 | uconv -x '::NFKD; \u0301>; ::NFKC;' | iconv -f utf-8
Run Code Online (Sandbox Code Playgroud)

能够在用户的语言环境中处理数据。