Sort

在 unicode 文本上使用 uniq

  • December 27, 2019

我想從帶有敘利亞語腳本單詞的文件中刪除重複的行。源文件有 3 行,第 1 和第 3 行是相同的。

$ cat file.txt 
ܐܒܘܢ
ܢܗܘܐ
ܐܒܘܢ

當我使用sortanduniq時,結果假定所有 3 行都是相同的,這是錯誤的:

$ cat file.txt | sort | uniq -c
     3 ܐܒܘܢ

將語言環境顯式設置為敘利亞語也無濟於事。

$ LC_COLLATE=syr_SY.utf8 cat file.txt | sort | uniq -c      
    3 ܐܒܘܢ

為什麼會這樣?如果這很重要,我正在使用 Kubuntu 18 和 bash。

uniq在 Ubuntu 上找到的 GNU 實現-c不報告連續相同行的計數,而是報告排序相同的連續行的計數¹。

GNU 系統上的大多數國際語言環境都有這樣的錯誤,即許多完全不相關的字元已使用相同的排序順序定義,其中大多數是因為根本沒有定義它們的排序順序。大多數其他作業系統確保所有字元都有不同的排序順序。

$ expr ܐ = ܒ
1

(expr=運算符,對於非數字參數,如果操作數排序相同,則返回 1,否則返回 0)。

這與ar_SY.UTF-8or相同en_GB.UTF-8

您需要的是一個區域設置,這些字元已被賦予不同的排序順序。如果 Ubuntu 有敘利亞語的語言環境,您可以期望這些字元被賦予不同的排序順序,但 Ubuntu 沒有這樣的語言環境。

您可以查看locale -a支持的語言環境列表的輸出。您可以通過執行dpkg-reconfigure localesas來啟用更多語言環境root。您還可以localedef根據 中的定義文件手動定義更多語言環境/usr/share/i18n/locales,但您將在那裡找不到敘利亞語的數據。

請注意,在:

LC_COLLATE=syr_SY.utf8 cat file.txt | sort | uniq -c

您只是為cat命令設置 LC_COLLATE 變數(這不會影響它輸出文件內容的方式,cat不關心排序規則,甚至不關心字元編碼,因為它不是文本實用程序)。您想同時為sort和設置它uniq。您還希望設置LC_CTYPE為具有 UTF-8 字元集的語言環境。

由於您的系統沒有syr_SY.utf8語言環境,這與使用C語言環境(預設語言環境)相同。

實際上,這裡的 C 語言環境或 C.UTF-8 可能是您想要使用的語言環境。

在這些語言環境中,排序順序基於程式碼點、C.UTF-8 的 Unicode 程式碼點、C 的字節值,但最終與 UTF-8 字元編碼具有該屬性相同。

$ LC_ALL=C expr ܐ = ܒ
0
$ LC_ALL=C.UTF-8 expr ܐ = ܒ
0

所以:

(export LANG=ar_SY.UTF-8 LC_COLLATE=C.UTF-8 LANGUAGE=syr:ar:en
unset LC_ALL
sort <file | uniq -c)

您將擁有一個以 UTF-8 作為字元集的 LC_CTYPE、基於程式碼點的排序規則以及與您所在地區相關的其他設置,例如,如果 GNU coreutilssortuniq消息已被翻譯成敘利亞語或阿拉伯語的錯誤消息語言(他們還沒有)。

如果您不關心其他設置,那麼使用起來同樣簡單(而且更便攜):

<file LC_ALL=C sort | LC_ALL=C uniq -c

或者

(export LC_ALL=C; <file sort | uniq -c)

正如@isaac 已經展示的那樣。


¹ 請注意,符合 POSIXuniq的實現並不意味著使用區域設置的排序算法比較字元串,而是進行字節到字節的相等比較。這在 2018 年版標準中得到了進一步澄清(請參閱相應的 Austin 組錯誤)。但 GNUuniq目前確實使用strcoll(),甚至在POSIXLY_CORRECT; 它還有一個-i不區分大小寫比較的選項,具有諷刺意味的是,它不使用語言環境資訊,只能在 ASCII 輸入上正常工作

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