Mengapa penyortiran mengabaikan karakter non-alfanumerik?

25

Saat menyortir nama file, lsabaikan karakter suka -,_. Saya berharap untuk menggunakan karakter-karakter itu dalam menyortir juga.

Sebuah contoh:

touch a1 a2 a-1 a-2 a_1 a_2 a.1 a.2 a,1 a,2

Sekarang tampilkan file-file ini dengan ls -1:

a1
a_1
a-1
a,1
a.1
a2
a_2
a-2
a,2
a.2

Apa yang saya harapkan adalah seperti ini:

a1
a2
a,1
a,2
a.1
a.2
a_1
a_2
a-1
a-2

yaitu saya berharap karakter non-alfanumerik diperhitungkan saat menyortir.

Adakah yang bisa menjelaskan perilaku ini? Apakah perilaku ini diamanatkan oleh standar? Atau ini karena pengkodean menjadi UTF-8?

Pembaruan: Tampaknya ini terkait dengan pengurutan UTF-8:

$ LC_COLLATE=C ls -1
a,1
a,2
a-1
a-2
a.1
a.2
a1
a2
a_1
a_2
daniel kullmann
sumber
2
UTF-8 dan ASCII identik jika semua yang Anda gunakan adalah 128 titik kode pertama (yang menjadi contoh Anda). Apa yang terjadi jika Anda melakukannya LC_COLLATE=C ls?
Alexios
Masalahnya bukan bahwa ASCII dan UTF-8 identik, melainkan bahwa UTF-8 memiliki aturan collation (sorting) sendiri.
daniel kullmann
1
Ya itu benar [_-,.] sedang dikelompokkan dan entah bagaimana semi-diabaikan. Saya tidak tahu persis bagaimana atau di mana pemeriksaan tersebut didefinisikan, tetapi harus menjadi masalah pemeriksaan, karena sederhana, dan hanya, mengubah pemeriksaan ke C (melalui LC_COLLATE=C ls -l) cukup untuk memberikan urutan yang Anda harapkan (dengan asumsi LC_ALLadalah tidak mengesampingkan LC_COLLATE). Ini berlaku untuk seluruh jajaran karakter di Unicode Basic Multilingual Plane ... Saya telah mengedit jawaban saya untuk menyertakan contoh skrip yang menghasilkan ini ...
Peter.O
jika Anda tidak suka cara kerjanya, Anda dapat membuat alias dan meletakkannya di ~ / .profile: alias ls = 'LC_COLLATE = C ls' </kbd>
jippie

Jawaban:

10

Ini tidak ada hubungannya dengan charset. Sebaliknya, itu adalah bahasa yang menentukan urutan susunan. Libc memeriksa bahasa yang disajikan dalam $LC_COLLATE/ $LC_ALL/ $LANGdan mencari aturan /usr/share/i18n/locales/*susunannya (misalnya untuk GLibC) dan memerintahkan teks sesuai petunjuk.

Ignacio Vazquez-Abrams
sumber
FYI: Ini lebih rumit dari ini. Jika seseorang menggunakan strcollmisalnya, Anda akan melihat bahwa sesuatu seperti aasa.cakan diurutkan di atas aas.c.
Don Scott
12

EDIT: Uji tambah untuk data yang diurutkan dengan LC_COLLATE = C


Urutan susunan default memperlakukan karakter "tipe tanda baca" tersebut memiliki nilai yang sama .. Use LC_COLLATE=Cuntuk memperlakukannya dalam urutan titik kode ..

for i in 'a1' 'a_1' 'a-1' 'a,1' 'a.1' 'a2' 'a_2' 'a-2' 'a,2' 'a.2' ;do
  echo $i; 
done |LC_COLLATE=C sort

Keluaran

a,1
a,2
a-1
a-2
a.1
a.2
a1
a2
a_1
a_2

Kode berikut menguji semua karakter UTF-8 yang valid di Basic Multilingual Plane (kecuali untuk \ x00 dan \ x0a ; untuk kesederhanaan)
Ia membandingkan file dalam urutan naik (dikenal) yang diketahui, terhadap file yang diurutkan secara acak dan kemudian diurutkan lagi dengan LC_COLLATE = C. Hasilnya menunjukkan bahwa urutan C identik dengan urutan asli yang dihasilkan.

{ i=0 j=0 k=0 l=0
  for i in {0..9} {A..F} ;do
  for j in {0..9} {A..F} ;do
  for k in {0..9} {A..F} ;do
  for l in {0..9} {A..F} ;do
     (( 16#$i$j$k$l == 16#0000 )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l == 16#000A )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l >= 16#D800    && 
        16#$i$j$k$l <= 16#DFFF )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l >= 16#FFFE )) && { printf '.' >&2; continue; }
     echo 0x"$i$j$k$l" |recode UTF-16BE/x4..UTF-8 || { echo "ERROR at codepoint $i$j$k$l " >&2; continue; } 
     echo 
  done
  done
  done; echo -n "$i$j$k$l " >&2
  done; echo >&2
} >listGen

             sort -R listGen    > listRandom
LC_COLLATE=C sort    listRandom > listCsort 

diff <(cat listGen;   echo "last line of listOrig " ) \
     <(cat listCsort; echo "last line of listCsort" )
echo 
cmp listGen listCsort; echo 'cmp $?='$?

Keluaran:

63485c63485
< last line of listOrig 
---
> last line of listCsort

cmp $?=0
Peter.O
sumber
2
Di mana itu didokumentasikan? Apakah itu bagian dari standar Unicode?
daniel kullmann
2
Sebenarnya, mereka tidak mendapatkan nilai yang sama; karakter-karakter itu diabaikan begitu saja ketika menyortir. Jika mereka diperlakukan memiliki nilai yang sama, urutan penyortiran a_1 a2 a_2tidak akan mungkin.
daniel kullmann
+1 untuk kerja keras dan kode sampel Anda. Setelah berjam-jam menyortir nama-nama direktori dengan tanda baca agar sesuai dengan cara treemelakukannya saya pikir ada lebih banyak cerita seperti tanda baca yang dihapus dari string perbandingan atau sesuatu seperti itu. Saya dapat mengatakan bahwa /karakter harus ditetapkan sebagai karakter terendah dalam urutan susun, apa pun yang terjadi.
WinEunuuchs2Unix