Unicode テキストで uniq を使用する

Unicode テキストで uniq を使用する

次の内容を含むファイルから重複した行を削除したいと思います。シリア語スクリプト。ソースファイルには3行があり、最初と3行は同じです。

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

sortandを使用すると、uniq結果は3つの行がすべて同じであると仮定しますが、これは間違っています。

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

ロケールを明示的にシリア語に設定することも役に立ちません。

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

なぜこれが起こるのですか?それが重要であれば、私はKubuntu 18とbashを使用しています。

ベストアンサー1

uniq-cUbuntuでのGNUの実装まったく同じ行ですが、同じ順序の連続行数です。

GNUシステムのほとんどの国際ロケールには、完全に関連していない多くの文字が同じソート順で定義されるバグがあります。ほとんどは、ソート順がまったく定義されていないためです。他のほとんどのオペレーティングシステムでは、すべての文字のソート順が異なります。

$ expr ܐ = ܒ
1

expr演算子=、数値以外の引数の場合、オペランドの順序が等しい場合は1を返し、それ以外の場合は0を返します)。

ar_SY.UTF-8これはまたはと同じですen_GB.UTF-8

必要なのは、これらの文字に異なる並べ替え順序が付与されたロケールです。 Ubuntuにシリア言語のロケールがある場合、これらの文字には別のソート順序が付与されると予想できますが、Ubuntuにはそのようなロケールはありません。

locale -aサポートされているロケールリストの出力を表示できます。dpkg-reconfigure localesとして実行して、より多くのロケールを有効にできますrootlocaledefの定義ファイルに基づいてより多くのロケールを手動で定義することもできますが、/usr/share/i18n/localesシリア語のデータは見つかりません。

次の点に注意してください。

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

コマンドにLC_COLLATE変数を設定するだけです。catこれはファイルの内容の出力方法に影響を与えず、catテキストユーティリティではないため、コントラストや文字エンコーディングにも興味がありません。sortとの両方を設定しようとしていますuniq。また、LC_CTYPEUTF-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 coreutilsまたはメッセージがその言語に翻訳されているsort場合uniq)などのロケールに関連するその他の設定があります。まだ持っていません)。

これらを気にしない場合その他設定と使いやすさとポータブルに優れています。

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

または

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

@isaacがすでに示したように。


1 POSIX準拠のuniq実装は、ロケールソートアルゴリズムを使用した文字列比較ではなく、バイト間の同等比較を意味します。これは2018年版の標準でより明確になりました(参照:対応するオースティングループエラー)。しかし、GNUはuniq現在これを使用しており、strcoll()大文字と小文字を区別しない比較オプションがPOSIXLY_CORRECTあります。-iこれは皮肉なことに、ロケール情報を使用せずにASCII入力でのみ正しく機能します。

おすすめ記事