Tentukan urutan pengurutan dengan LC_COLLATE sehingga huruf kecil adalah sebelum huruf besar

16

Diberikan file:

$ cat file
1
a
C
B
2
c
3
A
b

Secara default sortakan:

$ sort file
1
2
3
a
A
b
B
c
C

Dengan LC_COLLATE=Cbegitu akan mengurutkan huruf besar sebelum huruf kecil:

$ LC_COLLATE=C sort file
1
2
3
A
B
C
a
b
c

Apakah mungkin untuk mendapatkan semacam untuk membalikkan pemesanan kasus, yaitu digit, huruf kecil kemudian huruf besar?

iiSeymour
sumber

Jawaban:

8

Saya tidak tahu ada lokal yang secara default mengurutkan dalam urutan itu. Solusinya adalah membuat lokal kustom dengan urutan pengurutan yang disesuaikan. Jika ada orang, empat tahun kemudian, yang ingin memilah-milah pakaian adat, inilah triknya.

Sebagian besar lokal tidak menentukan urutan pengurutannya sendiri, melainkan menyalin urutan pengurutan yang ditentukan /usr/share/i18n/locales/iso14651_t1_commonsehingga Anda ingin mengeditnya. Daripada mengubah urutan pengurutan untuk hampir setiap lokal dengan memodifikasi yang asli iso14651_t1_common, saya sarankan Anda membuat salinan. Detail tentang cara kerja pengurutan dan cara membuat lokal kustom di $HOMEdirektori Anda tanpa akses root ditemukan dalam jawaban untuk pertanyaan serupa .

Lihatlah bagaimana adan Adipesan berdasarkan entri mereka di iso14651_t1_common:

<U0061> <a>;<BAS>;<MIN>;IGNORE # 198 a
<U0041> <a>;<BAS>;<CAP>;IGNORE # 517 A

bdan Bserupa:

<U0062> <b>;<BAS>;<MIN>;IGNORE # 233 b
<U0042> <b>;<BAS>;<CAP>;IGNORE # 550 B

Kita melihat bahwa pada lintasan pertama, keduanya adan Amemiliki simbol susun <a>, sedangkan keduanya bdan Bmemiliki simbol susun <b>. Sejak <a>muncul sebelum <b>masuk iso14651_t1_common, adan Adiikat sebelumnya bdan B. Lewat kedua tidak memutuskan ikatan karena keempat karakter memiliki simbol susun <BAS>, tetapi pada lintasan ketiga ikatan tersebut diselesaikan karena simbol susun untuk huruf kecil <MIN>muncul pada baris 3467, sebelum simbol susun untuk huruf besar <CAP>(baris 3488) . Jadi urutan berakhir sebagai a, A, b, B.

Mengganti simbol-simbol penyusun pertama dan ketiga akan mengurutkan huruf-huruf pertama dengan huruf besar-kecil (lebih rendah dari atas), kemudian dengan aksen ( <BAS>berarti tidak beraksen), kemudian dengan urutan abjad. Namun , keduanya <MIN>dan <CAP>sebelum digit angka, jadi ini akan memiliki efek yang tidak diinginkan dari menempatkan digit setelah huruf.

Cara termudah untuk menjaga digit lebih dulu sementara membuat semua huruf kecil datang sebelum semua huruf besar adalah dengan memaksa semua huruf untuk mengikat selama perbandingan pertama dengan mengatur mereka semua sama <a>. Untuk memastikan bahwa mereka mengurutkan menurut abjad dalam kasus, mengubah simbol susun terakhir dari IGNOREke simbol susun pertama saat ini. Mengikuti pola ini, aakan menjadi:

<U0061> <a>;<BAS>;<MIN>;<a> # 198 a

A akan menjadi:

<U0041> <a>;<BAS>;<CAP>;<a> # 517 A

b akan menjadi:

<U0062> <a>;<BAS>;<MIN>;<b> # 233 b

B akan menjadi:

<U0042> <a>;<BAS>;<CAP>;<b> # 550 B

dan seterusnya untuk surat-surat lainnya.

Setelah Anda membuat versi khusus iso14651_t1_common, ikuti instruksi dalam jawaban yang tertaut di atas untuk mengkompilasi lokal kustom Anda.

beandip
sumber
6

Pengaturan LC_COLLATE=Ctidak selalu cukup untuk mengurutkan huruf besar sebelum huruf kecil. Anda mungkin perlu mengatur LC_ALL=C.

Itu juga akan mempertimbangkan karakter non-alfanumerik dan bahkan karakter yang tidak dapat dicetak, tetapi jika Anda tidak ingin ada opsi -ddan -i(dijelaskan dalam man sort) untuk mematikannya.

Ini mungkin akan gagal dengan input multibyte, seperti UTF-8 dengan karakter non-ASCII.

Untuk mendapatkan huruf kecil (berurutan) sebelum huruf besar (berurutan), cara terbaik yang dapat saya pikirkan yang tidak melibatkan memecahkan bahasa pemrograman penuh adalah membalikkan huruf semua huruf sebelum penyortiran, dan membalikkannya kembali setelah itu.

tr 'a-zA-Z' 'A-Za-z' < file | LC_ALL=C sort | tr 'a-zA-Z' 'A-Za-z'
Hukum29
sumber
2

Saya bukan ahli tetapi saya belum pernah melihat lokal yang mendefinisikan pemeriksaan seperti ini. AFAIK susunan ini hanya dalam C di mana ia didasarkan pada nilai-nilai ASCII . (Biasanya saya hanya akan menyelesaikan ini dengan skrip.)

Namun, saya belum pernah melakukan ini tetapi Anda mungkin ingin melihat halaman manual localedef (1) dan locale (5) untuk mendapatkan pemahaman tentang bagaimana lokal didefinisikan dan akhirnya menentukan sendiri.

Juga jangan lupa bahwa jika ada diakritik atau karakter khusus, C locale tidak akan memperlakukan mereka seperti yang Anda inginkan. Misalnya, tidak akan diletakkan ádekat aatau Łdekat L. Dalam kasus seperti itu, bahasa ibu akan mungkin merupakan titik awal yang lebih baik.

Alois Mahdal
sumber
0

Saya percaya jawabannya adalah tanpa perlu LC_COLLATE diubah (artinya meninggalkan fungsi sebagai perilaku default):

sortir -f file

Ini berfungsi di Linux; silakan lihat bagian bantuan Anda untuk perintah jika Anda berada di Unix dan menjalankan versi yang berbeda. -f didefinisikan sebagai kasus pengabaian.

Terima kasih atas perbaikan cepat yang agak (& anehnya) dan edit ke tata bahasa yang salah tempat, Stephen Rauch.

1m.0g
sumber
-1
LC_COLLATE="en_US.UTF-8" sort file
unxnut
sumber
Ini tidak mengurutkan huruf kecil sebelum huruf besar? ideone.com/Gtyg4Z
iiSeymour
Hmm, dalam kasus saya, itu memang menggunakan contoh Anda.
unxnut
4
@unxnut Ini tidak benar. Tanpa titik koma, perintah akan mengatur lingkungan sort, tetapi dengan titik koma variabel lokal ke shell dan tidak mempengaruhi perilaku sort. Tanda titik koma dapat disimpan seolah-olah variabel juga diekspor, tetapi itu akan mempengaruhi perintah lain juga.
Anders Sjöqvist