如何让 tr 了解非 ascii(unicode)字符?

Mat*_*ock 38 linux text-processing unicode tr

我正在尝试从文件(UTF-8)中删除一些字符。我tr为此目的使用:

tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat 
Run Code Online (Sandbox Code Playgroud)

文件包含一些外来字符(如“??????????”或“àé”)。tr似乎不理解它们:它将它们视为非 alpha 并删除。

我试过更改我的一些语言环境设置:

LC_CTYPE=C LC_COLLATE=C tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
LC_CTYPE=ru_RU.UTF-8 LC_COLLATE=C tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
LC_CTYPE=ru_RU.UTF-8 LC_COLLATE=ru_RU.UTF-8 tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
Run Code Online (Sandbox Code Playgroud)

不幸的是,这些都没有奏效。

我怎样才能tr理解Unicode?

Sté*_*las 36

这是一个公知的(123456)的GNU实现的限制tr

与其说它不支持外来、非英语或非 ASCII 字符,不如说它不支持多字节字符。

如果以 iso8859-5(每个字符单字节)字符集(并且您的语言环境使用该字符集)编写,那么这些西里尔字符将被处理,但您的问题是您使用的是非 ASCII 的 UTF-8字符以 2 个或更多字节编码。

GNU 有一个计划(另请参阅参考资料)来解决这个问题,并且工作正在进行中,但还没有完成。

FreeBSD 或 Solaristr没有这个问题。


同时,对于 的大多数用例tr,您可以使用支持多字节字符的 GNU sed 或 GNU awk。

例如,您的:

tr -cs '[[:alpha:][:space:]]' ' '
Run Code Online (Sandbox Code Playgroud)

可以写成:

gsed -E 's/( |[^[:space:][:alpha:]])+/ /'
Run Code Online (Sandbox Code Playgroud)

或者:

gawk -v RS='( |[^[:space:][:alpha:]])+' '{printf "%s", sep $0; sep=" "}'
Run Code Online (Sandbox Code Playgroud)

要在大小写 ( tr '[:upper:]' '[:lower:]')之间转换:

gsed 's/[[:upper:]]/\l&/g'
Run Code Online (Sandbox Code Playgroud)

(这l是一个小写字母L,而不是1数字)。

或者:

gawk '{print tolower($0)}'
Run Code Online (Sandbox Code Playgroud)

对于便携性,perl是另一种选择:

perl -Mopen=locale -pe 's/([^[:space:][:alpha:]]| )+/ /g'
perl -Mopen=locale -pe '$_=lc$_'
Run Code Online (Sandbox Code Playgroud)

如果您知道数据可以用单字节字符集表示,那么您可以在该字符集中处理它:

(export LC_ALL=ru_RU.iso88595
 iconv -f utf-8 |
   tr -cs '[:alpha:][:space:]' ' ' |
   iconv -t utf-8) < Russian-file.utf8
Run Code Online (Sandbox Code Playgroud)

  • @IncnisMrsi,这里重要的是 ISO 8859-5 是具有这些西里尔字符的单字节字符集之一。它是否被广泛使用在这里无关紧要。如果您的语言环境带有 KOI-R 或 window-1251 字符集,请务必改用它。 (9认同)
  • @MatthewRock 我保留了它,但对其进行了重新措辞并使其更加通用,因为给出一个词对有相同问题的人很有用。 (3认同)

Rai*_*ahs 5

只需使用 GNU sed (具有适当的LANG环境变量,例如en_US.UTF-8):

\n
% sed 'y/123/abc/; y/\xc4\x81\xc5\x8d\xc4\xab/456/' <<< test123ingm\xc4\x81\xc5\x8d\xc4\xab\ntestabcingm456\n
Run Code Online (Sandbox Code Playgroud)\n