似乎sort
在诸如以下的线路上表现得很奇怪>>b
$ cat test
a
>>b
b
c
>
>>
$ sort test
>
>>
a
b
>>b
c
我希望该>>b
行是第三行输出,sort
但它是第五行。为什么它会这样做,有没有办法sort
给出我的预期输出?
我正在使用 GNU/Linux Ubuntu 16.04。
答案1
现代语言环境中的排序算法非常复杂。
每个角色(实际上整理元素它可以由几个字符的序列组成,例如捷克语ch
)被赋予了一些整理权重决定它们的排序顺序。
比较两个字符串时,首先使用所有字符的第一个权重,然后使用其他权重来确定两个字符串与第一个权重排序相同的情况。
例如,在许多语言环境中,e
、é
和E
具有相同的基本的重量(它们属于相同的等价类,它们都匹配[=e=]
)。
因此,当比较例如echo
、été
和 时Enter
,在第一遍中,e
和é
具有E
相同的主要权重,第二个字符将决定顺序(c
before n
before t
)。
在第一遍之后比较été
, Été
, , 时,它们的排序相同,因此我们使用次要权重来使用第二遍。Ete
在典型的 GNU 语言环境中,拉丁脚本字符的第二个权重用于确定重音的优先级(无重音优先,然后是锐音、重音、短音、抑音音……)。然后,我们需要使用第三个权重来决定été
和 ,Été
并且这将基于大小写(在大多数语言环境中先小写)。甚至有些字符最终排序相同,因为它们的权重都相同。
它用于以与字典类似的方式对文本进行排序,就像人类所做的那样。
在字典中,您会发现空格和大多数标点符号也被忽略。例如de facto
在debut
和之间排序devoid
。空格字符的第一个权重是 IGNORE。
/usr/share/i18n/locales/iso14651_t1_common
在 GNU 系统上,您将在(路径可能因发行版而异)中找到定义的核心排序规则。在那里,您将看到:
ifdef UPPERCASE_FIRST
<CAP>
else
<MIN>
endif
[...]
ifdef UPPERCASE_FIRST
[...]
<MIN> # 10
[...]
else
[...]
<CAP> # 9
[...]
endif
[...]
order_start <SPECIAL>;forward;backward;forward;forward,position
<U0020> IGNORE;IGNORE;IGNORE;<U0020> # 32 <SP>
[...]
<U003E> IGNORE;IGNORE;IGNORE;<h> # 140 >
[...]
ifdef DIACRIT_FORWARD
order_start <LATIN>;forward;forward;forward;forward,position
else
order_start <LATIN>;forward;backward;forward;forward,position
endif
[...]
<U0065> <e>;<BAS>;<MIN>;IGNORE # 259 e
<U00E9> <e>;<ACA>;<MIN>;IGNORE # 260 é
[...]
<U0045> <e>;<BAS>;<CAP>;IGNORE # 577 E
<U00C9> <e>;<ACA>;<CAP>;IGNORE # 578 É
这说明了我们刚才所说的。两者的空间和>
前 3 个权重都设置为IGNORE
。仅对于前 3 个权重排序相同的字符串,才会考虑它们的相对顺序(>
在空格之前,因为它将<h>
在未指定的整理符号之前列出<U0020>
)。
在定义的语言环境中UPPERCASE_FIRST
(例如/usr/share/i18n/locales/tr_TR
),大写字母将首先出现(在第三遍中)。与DIACRIT_FORWARD
某些语言环境一样,de_DE
可以决定颠倒第二遍的变音符号顺序。
>
并 在第 1、2和3遍中>>
进行相同的排序。在第四个中,在之前排序,因为空字符串在所有内容之前排序。>
>>
>>b
之后排序,b
因为它们在前 3 遍中排序相同,但在第四遍中b
为 IGNORE,因此>
更大。它比c
第一遍(>
忽略和b
之前)要少c
......你明白了。
现在,如果您查看C
区域设置定义。简单多了。只有一个权重,并且该权重基于从 U+0000 到 U+10FFFF 的代码点值。因此,SPC
(U+0020) 排序在>
(U+003E) 之前,(U+003E) 排序在b
(U+0062) 之前,而 (U+0063) 排序在c
(U+0063) 之前。没有一个角色会被忽视。
请注意,至少对于 GNU libc,当涉及比较函数(strcoll()
以及 所使用的 co. sort
)时,C 语言环境定义文件中定义的顺序将被忽略。无论 的值如何LC_CTYPE
,与LC_COLLATE=C
,strcoll()
都等同于strcmp()
。因为比较始终针对字节值,即使这些字节对应于 unicode 代码点以相反方式排序的字符(例如 ISO-8859-15 字符集中的 0xA4 U+20AC EURO SIGN 与 A5 U+00A5 YEN SIGN) ,因此LC_ALL=C sort
和LC_COLLATE=C sort
(LC_ALL
如果没有另外设置)将具有相同的效果。
答案2
从sort(1)
手册页:
*** WARNING *** The locale specified by the environment affects sort order. Set
LC_ALL=C to get the traditional sort order that uses native byte values.
因此,要按字节值排序,请使用:
LC_ALL=C sort test
否则,sort
将忽略前导字符,直到遇到可以排序的键,这就是>>b
和b
最终彼此相邻的原因。