
私は Ubuntu 18.04 とデフォルトの coreutils を使用しています。sort
コマンドの特定の動作に気付きましたが、どのように説明すればよいかわかりません。
次のコマンドを考えてみましょう。
$ cat <<EOF | sort
0-
01-
EOF
0-
01-
この出力は意味をなします。-
は ASCII 値よりも小さいため1
、この出力が予想されます。
ただし、最後にもう 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
したがって、ソート時に LC_COLLATE=C を使用して、常に「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
次のようなことを"
実行する必要があります。
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
つまり、照合の最初の 3 つのレベルを無視します。