
我使用的是 Ubuntu 18.04 和預設的 coreutils。我注意到該命令的一個特殊行為sort
,我不確定如何解釋。
考慮以下命令:
$ cat <<EOF | sort
0-
01-
EOF
0-
01-
此輸出是有意義的,因為-
ASCII 值小於預期值1
,因此此輸出是預期的。
但是,如果我在最後多加一個字元:
$ cat <<EOF | sort
0-T
01-T
EOF
01-T
0-T
這個輸出對我來說沒有任何意義,因為我認為0-T
應該放在第一位。為什麼會出現這種情況。我在這裡缺少什麼?我的期望是錯的嗎?
答案1
這取決於您所在區域的排序規則。
整理順序是針對每個區域設定的一組規則,允許對重音字母進行排序(例如,在西班牙語中將ñ
出現在之後n
但之前o
)。
但事實並非如此,排序規則也規定了排序時要忽略哪些字元。對於語言環境“C”,會考慮所有字符,但對於“en_US”,例如,對於大多數其他語言環境,破折號(U002D) 會被忽略,因為它們繼承了iso14651_t1_common 的定義(在/usr/share/ 下) i18n/locales/ 在某些發行版中)。
因此,第一個檔案的排序不會造成問題,因為當您忽略破折號時,您最終會得到簡單的字母比較:
-- ignore dashes --> -- sort -->
0- 0 0
01- 01 01
當你添加“T”時,事情發生了變化,為什麼?因為現在,如果您忽略破折號,則必須比較“1”和“T”(第一個字元相同),並且“1”位於“T”之前:
-- ignore dashes --> -- sort -->
0-T 0T 01T
01-T 01T 0T
因此,最好始終確保使用“C”的規則,並在排序時使用 LC_COLLATE=C。
在你的情況下:
$ cat <<EOF | LC_COLLATE=C sort
0-T
01-T
EOF
產量:
0-T
01-T
正如你所料。
答案2
是的,這可能看起來很煩人。 (預設語言環境為 en_US.UTF-8)
$ printf '%s\n' 1 1- 1-a 11- 11-a | sort
1
1-
11-
11-a
1-a
原因是 已-
分配no weight
給整理順序。
類似 a"
應該做的事情:
printf '%s\n' 1 \"1\" 1- \"1-\" 1-a \"1-a\" 11- \"11-\" 11-a \"11-a\" | sort
"1"
"1-"
1
1-
"11-"
11-
"11-a"
11-a
"1-a"
1-a
正如您在上面看到的,所有 1 都排序在一起,11
也全部。問題是它的1-a
排序1a
比其他任何東西都更像:
printf '%s\n' 1-a 1-b 1-c 1a 1b 1c| sort
1-a
1a
1-b
1b
1-c
1c
無論標點(-
、"
和;
其他)是否應該包含在排序規則排序順序中是有爭議的。普遍的觀點是不應該(在非 ASCII 語言環境中)。
這常見的大多數拉丁語言的文件是/usr/share/i18n/locales/iso14651_t1_common
.在該文件中HYPHEN-MINUS
(是的,用外行術語來說,我們稱之為破折號。Unicode U-002D)整理順序設定為:
<U002D> IGNORE;IGNORE;IGNORE;<U002D> % HYPHEN-MINUS
也就是說,忽略前三個等級的整理。