web-dev-qa-db-ja.com

en_US.UTF-8ロケールでの予期しないソート順

回答しようとしたところ、 SQLの並べ替えに関するこの質問 に、予期しないsortの順序に気づきました。

$ export LC_ALL=en_US.UTF-8  
$ echo "T-700A Grouped" > sort.txt
$ echo "T-700 AGrouped" >> sort.txt
$ echo "T-700A Halved" >> sort.txt
$ echo "T-700 Whole" >> sort.txt
$ cat sort.txt | sort
T-700 AGrouped
T-700A Grouped
T-700A Halved
T-700 Whole
$ 

700 A700Aの上にあるのに、700A700 Wの上に並べ替えられているのはなぜですか?それに続く文字とは関係なく、Aの前にスペースが一貫して来ることを期待します。

Cロケールを使用すると、正常に機能します。

$ export LC_ALL=C
$ echo "T-700A Grouped" > sort.txt
$ echo "T-700 AGrouped" >> sort.txt
$ echo "T-700A Halved" >> sort.txt
$ echo "T-700 Whole" >> sort.txt
$ cat sort.txt | sort
T-700 AGrouped
T-700 Whole
T-700A Grouped
T-700A Halved
$ 
7
Andomar

トリックは、いわば、ソートが複数のパスで行われるということです。すべての文字には、3つ(場合によってはそれ以上)の重みが割り当てられています。この例では、重みが次のようになっているとしましょう。

space = [0000.0020.0002]
A     = [1BC2.0020.0008]

ソートキーを作成すると、文字列の文字のゼロ以外の重みが、一度に1つの重みレベルで連結されます。つまり、重みがゼロの場合、対応する重みは追加されません(" A"の最初に見られるように)。そう

" A" = 1BC2 0020 0020 0002 0008
"A"  = 1BC2 0020 0008
"A " = 1BC2 0020 0020 0008 0002

これらの配列を並べ替えると、次のような順序になります。

1BC2 0020 0008           => "A"
1BC2 0020 0020 0002 0008 => " A"
1BC2 0020 0020 0008 0002 => "A "

これは実際に起こることを単純化したものです。詳細については、 nicode Collat​​ion Algorithm を参照してください。上記の例の重みは実際には標準テーブルからのもので、一部の詳細は省略されています。

10