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
这是一个公知的(1,2,3,4,5,6)的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)
只需使用 GNU sed (具有适当的LANG
环境变量,例如en_US.UTF-8
):
% 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