en_US.UTF-8 语言环境中的意外排序顺序

And*_*mar 10 sort glibc locale

在尝试回答这个关于 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
$ 
Run Code Online (Sandbox Code Playgroud)

为什么700 A排序在上面700A,而700A在上面700 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
$ 
Run Code Online (Sandbox Code Playgroud)

Pet*_*aut 13

排序是通过多次完成的。每个角色都有三个(或有时更多)分配给它的权重。让我们说这个例子的权重是

         wt#1 wt#2 wt#3
space = [0000.0020.0002]
A     = [1BC2.0020.0008]
Run Code Online (Sandbox Code Playgroud)

为了创建排序键,字符串字符的非零权重被连接起来,一次一个权重级别。也就是说,如果权重为零,则不会添加相应的权重(如 开头所示" A")。所以

       wt#1   -- wt#2 ---   -- wt#3 ---
" A" = 1BC2   0020   0020   0002   0008
       A      sp     A      sp     A

       wt#1   wt#2   wt#3
"A"  = 1BC2   0020   0008
       A      A      A

       wt#1   -- wt#2 ---   -- wt#3 ---
"A " = 1BC2   0020   0020   0008   0002
       A      A      sp     A      sp
Run Code Online (Sandbox Code Playgroud)

如果您对这些数组进行排序,则会得到您看到的顺序:

       1BC2   0020   0008               => "A"
       1BC2   0020   0020   0002   0008 => " A"
       1BC2   0020   0020   0008   0002 => "A "
Run Code Online (Sandbox Code Playgroud)

这是对实际情况的简化;有关更多详细信息,请参阅Unicode 整理算法。上面的示例权重实际上来自标准表,省略了一些细节。