Linux
如何讓 tr 知道非 ascii(unicode) 字元?
我正在嘗試從文件(UTF-8)中刪除一些字元。我
tr
為此目的使用:tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
文件包含一些外來字元(如“Латвийская”或“àé”)。
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
不幸的是,這些都不起作用。
我怎樣才能
tr
理解 Unicode?
與其說它不支持外語、非英語或非 ASCII 字元,不如說它不支持多字節字元。
如果以 iso8859-5(每個字元單字節)字元集(並且您的語言環境使用該字元集)編寫,那些西里爾字元將被處理好,但您的問題是您使用的是非 ASCII 的 UTF-8字元編碼為 2 個或更多字節。
GNU 有一個計劃(另請參見參考資料)來解決這個問題,並且工作正在進行中,但還沒有完成。
FreeBSD 或 Solaris
tr
沒有問題。同時,對於 的大多數案例
tr
,您可以使用支持多字節字元的 GNU sed 或 GNU awk。例如,您的:
tr -cs '[[:alpha:][:space:]]' ' '
可以寫成:
gsed -E 's/( |[^[:space:][:alpha:]])+/ /'
或者:
gawk -v RS='( |[^[:space:][:alpha:]])+' '{printf "%s", sep $0; sep=" "}'
要在大小寫 (
tr '[:upper:]' '[:lower:]'
) 之間進行轉換:gsed 's/[[:upper:]]/\l&/g'
(這
l
是一個小寫字母L
,而不是1
數字)。或者:
gawk '{print tolower($0)}'
為了便攜性,
perl
是另一種選擇:perl -Mopen=locale -pe 's/([^[:space:][:alpha:]]| )+/ /g' perl -Mopen=locale -pe '$_=lc$_'
如果您知道數據可以用單字節字元集表示,那麼您可以在該字元集中處理它:
(export LC_ALL=ru_RU.iso88595 iconv -f utf-8 | tr -cs '[:alpha:][:space:]' ' ' | iconv -t utf-8) < Russian-file.utf8