unicode 字符的 tr 模拟?

unicode 字符的 tr 模拟?

我需要国际化实用程序执行与以下操作相同的操作tr:从流中获取字符并将其替换为相应的字符。不需要像从下到上这样的特定案例解决方案,而是需要通用案例解决方案。如果可能的话,没有大猩猩管道sed调用。

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

$ tr --version | head -n 1
tr (GNU coreutils) 8.23
$ echo $LC_CTYPE
en_US.UTF-8
$ echo 'Ångstrom' | tr Æ Œ         
Ņngstrom

答案1

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

$ echo é½Æ | sed 'y/é½Æ/ABŒ/'
ABŒ

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

更多相关信息,请访问如何让 tr 识别非 ascii(unicode) 字符?

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

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

请注意,sed'sy不支持像a-z.另请注意,如果包含的脚本sed 'y/é½Æ/ABŒ/'是用 UTF-8 字符集编写的,则在非 UTF-8 字符集的语言环境中调用该脚本将不再按预期工作。

另一种方法是使用perl

perl -Mopen=locale -Mutf8 -pe 'y/a-zé½Æ/A-ZABŒ/'

上面,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/♣\`/&'/"

在字符集为 BIG5-HKSCS 的语言环境中会失败,因为 (0x5c) 的编码\也恰好包含在其他一些字符中(例如α:0xa3 0x5c,而 UTF-8 编码恰好以 0xa3 结尾)。

无论如何,不​​要期望像这样的事情

perl -Mopen=locale -Mutf8 -pe 'y/Á-Ź/A-Z/'

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

perl -Mopen=locale -Mutf8 -pe 'y/\x{c1}-\x{179}/\x{41}-\x{5a}/'

也就是说,范围基于 unicode 代码点。因此,范围在恰好位于“”中的定义明确的序列之外没有用处。正确的“Unicode 中的顺序如A-Z, 0-9.

如果您想删除尖锐的口音,您必须使用更高级的工具,例如:

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

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

音译 U​​nicode 的另一个有用工具uconv来自重症监护室。例如,上式也可以写成:

uconv -x '::NFKD; \u0301>; ::NFKC;'

但仅适用于 UTF-8 数据。你需要:

iconv -t utf-8 | uconv -x '::NFKD; \u0301>; ::NFKC;' | iconv -f utf-8

能够在用户的区域设置中处理数据。

答案2

在 Bash 中,您可以使用参数扩展

替换Å成功:

$ string='Hello Ångstrom'
$ a='Å'
$ b='Œ'
$ printf '%s\n' "${string//${a}/${b}}"
Hello Œngstrom

尝试替换Æ,它不是字符串的一部分:

$ string='Hello Ångstrom'
$ a='Æ'
$ b='Œ'
$ printf '%s\n' "${string//${a}/${b}}"
Hello Ångstrom

答案3

这可能是你的编码方案。尝试通过 iconv 运行它,如下所示:

echo Ångstrom | iconv -f UTF-8 | tr 'Å' 'Œ'

推出: Œngstrom

相关内容