LinuxソートコマンドはCとC.utf-8ロケールを区別しますか?
ソートマニュアルでは、LC_ALL = Cを使用してバイト値でソートしますが、C.utf-8は(ASCIIだけでなく)utf8値も受け入れることがわかります。ただし、ソートマニュアルはこのロケールオプションをまったく参照しません。
LC_ALL=C sort file.txt と LC_ALL=C.utf8 sort file.txt を実行すると、2 つの間に違いは見られません。どちらもファイルにutf 8文字があるかどうかに関係なく動作するようです。
では、既知の違いがありますか?
ベストアンサー1
LC_ALL=C sort
バイト値でソートします。 ASCII1 だけでなく、すべての文字セットで作成された入力をバイト値でソートします。
UTF-8エンコーディングには、Unicodeコードポイントでソートするのと同じバイト値でソートする属性があります(memcmp()
U + 1234より大きいエンコーディングまたは0x1234より小さいUnicodeコードポイントを見つけることができます)。
C.utf-8
または(私の経験では、後者はより一般的です)POSIX標準化されていないロケールですが、見つかった場所ごとに文字セットがUTF-8であることを除いて、Cロケールのほとんどの属性を持つロケールを意味しますC.utf8
。C.UTF-8
LC_ALL=C.UTF-8 sort
入力はコードポイントに基づいてソートされますが、比較する前にUTF-8をデコードするかstrcoll()
重いstrxfrm()
システムを呼び出すことになり、最終的にUTF-8の場合を使用するだけでmemcmp()
十分です。
sort
GNUとLinuxをカーネルとして使用する多くの非埋め込みオペレーティングシステムのlibc
使用sort
strcoll()
$ printf 'a\0£1\na\0€2\n' | LC_ALL=C ltrace -e strcoll -e memcmp sort
sort->memcmp("a\0\302\2431", "a\0\342\202\254", 5) = -1
a£1
a€2
$ printf 'a\0£1\na\0€2\n' | LC_ALL=C.UTF-8 ltrace -e strcoll -e memcmp sort
sort->strcoll("a", "a") = 0
sort->strcoll("\302\2431", "\342\202\2542") = -31
a£1
a€2
(実際に比較したい2つの文字列のバイト数が等しい場合、GNUは2つの文字列が同じ場合は呼び出す前に呼び出しsort
ます。これに比べてコストが安いからです。)memcmp()
strcoll()
memcmp()
strcoll()
この出力のいくつかのタイミングは1,000,000回繰り返されます。
$ printf 'a\0£1\na\0€2\n%.0s' {1..1000000} > file.test
$ wc -mc file.test
10000000 13000000 file.test
$ time LC_ALL=C sort file.test > /dev/null
LC_ALL=C sort file.test > /dev/null 0.74s user 0.06s system 390% cpu 0.205 total
$ time LC_ALL=C.UTF-8 sort file.test > /dev/null
LC_ALL=C.UTF-8 sort file.test > /dev/null 6.04s user 0.12s system 522% cpu 1.179 total
したがって、UTF-8でエンコードされたテキストをコードポイントで並べ替えるには、使用するか機能的にC
違いC.UTF-8
はありませんが、実装C
に応じて使用する方が効率的です。sort
これで、すべてのバイトシーケンスが有効なUTF-8を形成するわけではないため、UTF-8以外の入力(つまりUTF-8でデコードできないバイトシーケンスを含む入力)が含まれる場合の動作に違いがあります。あります。C
それでもC.UTF-8
GNUシステムでは:
$ print -l 'a\200b' 'a\201b' | LC_ALL=C sort -u
a�b
a�b
$ print -l 'a\200b' 'a\201b' | LC_ALL=C.UTF-8 sort -u
a�b
(ここで�は私の端末エミュレータが知らないことを表現したものです)
C.UTF-8でstrcoll()
有効なUTF-8テキストを形成しない2つの文字列に対して0を返すと、実際には同じソート順を持つと報告されます。
C言語環境では、LINE_MAX
ゼロ以外のバイト列で構成され、長さがバイトを超えない行はすべて有効なテキストです。 C.UTF-8には追加の制限があります。これはa\200b
UTF-8 では無効であるためテキストではないため、sort
POSIX では対応するアクションは指定されません。
ちなみに、GNUシステムではメッセージング言語よりもLC_ALL=C
優先されますが、優先順位はありません。$LANGUAGE
LC_ALL=C.UTF-8
$ LC_ALL=C LANGUAGE=fr:es:en sort /
sort: read failed: /: Is a directory
$ LC_ALL=C.UTF-8 LANGUAGE=fr:es:en sort /
sort: échec de lecture: /: est un dossier
また、C
ロケール文字セットはASCIIに基づいている必要はなく、ASCIIには0から127までの値のみが含まれていることに注意してください。C
ASCIIを使用するロケールは未定義の文字ですが、まだバイト128〜255を文字として扱います。ただし、ロケールC
文字セットは文字ごとに1バイトを保証する必要があるため、C
ロケール文字セットはUTF-8にすることはできません。