簡體   English   中英

對具有相同列的兩個文件進行排序將給出不同的排序

[英]Sorting two files that have the same column gives different sorting

標題很抱歉,但我不知道如何解釋:

我正在嘗試對兩個文件進行排序,因為我想將它們合並,它們看起來像這樣:

test1.txt

rs1010735   224915429
rs1010805   38189142
rs10108     114516330
rs1010863   185432942
rs1010891   110712154
rs1010910   61212213
rs1011124   7533164

test2.txt

rs1010735 C
rs1010805 T
rs1010863 T
rs1010891 T
rs10108  C
rs1010910 A
rs1011124 A

我使用sort -k1 test1.txtsort -k1 test2.txt並得到以下信息:

test1_sort.txt

rs1010735   224915429
rs1010805   38189142
rs10108 114516330
rs1010863   185432942
rs1010891   110712154
rs1010910   61212213
rs1011124   7533164

test2_sort.txt

rs1010735   C
rs1010805   T
rs1010863   T
rs1010891   T
rs10108     C
rs1010910   A
rs1011124   A

如果前兩列都具有相同的值,為什么會有不同的排序方式。

我也嘗試了sort -n -s k1,1但是得到了相同的結果。

添加空格:

$ sort -k 1,1 /tmp/2
rs1010735 C
rs10108  C
rs1010805 T
rs1010863 T
rs1010891 T
rs1010910 A
rs1011124 A
$ sort -k 1,1 /tmp/1
rs1010735   224915429
rs10108     114516330
rs1010805   38189142
rs1010863   185432942
rs1010891   110712154
rs1010910   61212213
rs1011124   7533164

這里有兩個問題。

語言環境感知排序

從根本上講,這里的問題是,您正在根據“語言環境”進行排序,該語言環境可能是en_US.UTF-8 (或其他一些Unicode語言環境)。 從理論上講,可識別區域設置的排序將根據該位置的常規排序規則產生預期的排序,而不會感知區域的排序將根據每個字符的“任意”字符代碼進行排序。

例如,在對語言環境敏感的排序中,通常以大寫字母開頭的單詞緊跟在以小寫字母開頭的同一個單詞之前(或之后),而對非語言環境敏感的排序將所有以大寫字母開頭的單詞放在任何以小寫字母開頭的單詞之前。 此外,在講英語的語言環境中,您可能會發現以ä開頭的單詞與以a開頭的單詞混合在一起,而在瑞典語的語言環境中,您會在以z開頭的單詞之后找到它們,因為在瑞典語中, ä是第28位字母(如果您有興趣,它可以在å之后和ö之前)。

為了使所有工作正常進行,計算機上的語言環境描述需要實際描述每個語言環境中期望的排序順序,尤其是默認語言環境(應與期望的語言環境相對應)。 從該示例可以看出,有時並非如此。 確實,它有時會產生令人驚訝的意外結果。

在您的示例中發生的是,您的語言環境的語言環境描述指出空白不參與排序 它還指示數字在字母之前。 現在,考慮數據的子集(兩個文件合並):

rs10108     114516330
rs1010805   38189142
rs1010863   185432942
rs10108     C
rs1010805   T
rs1010863   T

如果我們完全消除空白,那就是:

rs10108114516330
rs101080538189142
rs1010863185432942
rs10108C
rs1010805T
rs1010863T

然后,如果我們按照正常的字母規則(以數字開頭)對它進行排序,則會得到:

rs101080538189142
rs1010805T
rs10108114516330
rs1010863185432942
rs1010863T
rs10108C

或者,將空格放回原處:

rs1010805   38189142
rs1010805   T
rs10108     114516330
rs1010863   185432942
rs1010863   T
rs10108     C

這些是遵循的規則排序,結果是第一個字段為rs10108的兩行未一起排序。 違反直覺的,不是嗎?

可能正確的解決方案是告訴任何為您的發行版構建語言環境文件的人,通常的規則是“什么都沒有(可見)在某事之前”,這是我們在學校教過的字母化規則。 換句話說,在任何字符之前都有一個空格(看不見)。 或者,您可以嘗試自己修復歸類文件。

但實際上,解決方案是告訴sort默認情況下執行非語言環境感知的排序。 我這樣做是:

export LC_COLLATE=C

在我的bash啟動文件中。 C是與編程語言“ C”相對應的語言環境的特殊名稱,其中,符號按其內部字符代碼排序。)您還可以在每次要排序的內容時都鍵入該符號:

LC_COLLATE=C sort test1.txt

-k參數的含義

要排序的-k參數具有基本語法:

-k [ , ]

位置的start位置(以及可選的end位置)定義了用作排序鍵的文本范圍。 如果未指定end ,則范圍將繼續到該行的末尾。

頭寸的最簡單形式只是一個字段編號,例如1 ,表示“第一個字段”。 但是-k1 ,因為它的意思是“使用從第一個字段到行尾的文本”,這與說“將整個行用作排序鍵”基本相同,這是默認設置。 因此,每當您看到-k1您都應該知道它沒有達到預期的效果。

明確指定結尾將更加精確: -k1,1表示排序鍵是從第一個字段的(開始)到第一個字段的(結束),或者換句話說,第一個字段的文本。 這樣會更好,但不會提供有關如何對具有相同第一字段的兩行進行排序的任何提示。 默認情況下,標准的sort實用程序不是“穩定的”,因此無法預測將對這兩行進行排序的順序。 通常最好添加更多的二級排序字段:

sort -k1,1 -k2,2 

這實際上是“按第一個字段排序,但如果第一個字段相等,則比較第二個字段”。

字段在sort -k1,2分割(即使將空白忽略以進行排序),因此上述內容與sort -k1,2不同之處在於,可以確保將具有相同值的行放在連續位置的第一個字段中。


附錄:為什么語言環境在排序時會忽略空格

不幸的是, sort -k1,1 -k2,2也可能不是你想要的東西,特別是如果你做到這一點,在“C”語言環境,因為使用的排序字段的歷史定義的sort 除非使用-t選項指定了明確的定界符,否則排序字段將以每個非空格字符后的空格字符開頭。 因此,除第一個字段外的所有字段都以空格開頭。 如果它們都以相同的空格開頭,那很好,但是通常通過顯式添加正確數量的空格字符來排列字段。 而且這幾乎總是對除第一個字段以外的其他字段產生不正確的排序。

由於通常不需要這樣做,因此sort提供了一種抑制這種煩人行為的方式: b sort-key標志(sort key標志位於-k規范的末尾)。 該標志指示sort忽略排序鍵中的前導空格。 另外,您可以在將所有排序鍵中指定的任何-k選項之前都將-b指定為命令行選項,將其視為具有b標志。 這表明對sort的正確調用將是:

sort -k1,1 -k2,2b

要么

sort -b -k1,1 -k2,2

有人認為必須一直指定b令人討厭(因為幾乎總是您想要的),並且向用戶解釋為什么必須這樣做很麻煩。 因此,設置語言環境定義以忽略空白似乎更容易,這肯定會導致忽略主要空白。 該“解決方案”的問題在於,它產生的結果至少令人困惑,因為sort導致的結果包括字段定義中字段之間的空格,但由於沒有簡單的方法來解決,因此更難解決修改語言環境的排序規則。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM