Unicode

用於unicode字元的tr模擬?

  • December 5, 2017

我需要與以下功能相同的國際化實用程序tr:從流中獲取字元並將其替換為相應的字元。不是像從下到上的特定案例解決方案,而是需要一般案例解決方案。如果可能的話,沒有 gorillion 管道sed呼叫。

請注意,tr這在 Linux 上不起作用:它轉換字節,而不是字元。多字節編碼失敗。

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

GNUsed確實可以處理多字節字元。所以:

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

不是 GNUtr沒有國際化,而是它不支持多字節字元(如 UTF-8 語言環境中的非 ASCII 字元)。只要它們像 iso8859-15 字元集中那樣是單字節的,GNUtr就可以使用。Æ``Œ

更多關於如何讓 tr 了解非 ascii(unicode) 字元?

無論如何,這與Linux無關,它tr與系統上的實現有關。該系統是使用 Linux 作為核心還是tr為 Linux 建構或使用 Linux 核心 API 並不相關,因為這部分tr功能發生在使用者空間中。

busyboxtr和 GNUtr是為 Linux 建構的軟體發行版中最常見的,它們不支持多字節字元,但還有其他一些已移植到 Linux tr,例如 heirloom toolchest(從 OpenSolaris 移植)或 ast-打開那個做。

請注意,sedy不支持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)並重新組合。

另一個用於音譯 Unicode 的有用工具uconv來自ICU。例如,上面的也可以寫成:

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

雖然只適用於 UTF-8 數據。你需要:

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

能夠在使用者的語言環境中處理數據。

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