Linux

如何讓 tr 知道非 ascii(unicode) 字元?

  • July 14, 2021

我正在嘗試從文件(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?

這是. _ _ _ _ _ _ _ _ _ _ _tr

與其說它不支持外語、非英語或非 ASCII 字元,不如說它不支持多字節字元。

如果以 iso8859-5(每個字元單字節)字元集(並且您的語言環境使用該字元集)編寫,那些西里爾字元將被處理好,但您的問題是您使用的是非 ASCII 的 UTF-8字元編碼為 2 個或更多字節。

GNU 有一個計劃(另請參見參考資料)來解決這個問題,並且工作正在進行中,但還沒有完成。

FreeBSD 或 Solaristr沒有問題。


同時,對於 的大多數案例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

引用自:https://unix.stackexchange.com/questions/228558