Tidak dapat menggunakan `cut -c` (` --characters`) dengan UTF-8?


15

Perintah cutmemiliki opsi -cuntuk bekerja pada karakter, alih-alih byte dengan opsi -b. Tapi sepertinya itu tidak berhasil, di en_US.UTF-8tempat:

Byte kedua memberikan karakter ASCII kedua (yang dikodekan sama di UTF-8):

$ printf 'ABC' | cut -b 2          
B

tetapi tidak memberikan karakter kedua dari tiga karakter non-ASCII Yunani di lokal UTF-8:

$ printf 'αβγ' | cut -b 2         
�

Tidak apa-apa - ini byte kedua .
Jadi kita melihat karakter kedua sebagai gantinya:

$ printf 'αβγ' | cut -c 2 
�

Itu terlihat rusak.
Dengan beberapa percobaan, rentang tersebut 3-4menunjukkan karakter kedua:

$ printf 'αβγ' | cut -c 3-4
β

Tapi itu sama dengan byte 3 hingga 4:

$ printf 'αβγ' | cut -b 3-4
β

Jadi -ctidak lebih dari -buntuk UTF-8.

Saya berharap pengaturan lokal tidak tepat untuk UTF-8, tetapi sebagai perbandingan, wcberfungsi seperti yang diharapkan;
Ini sering digunakan untuk menghitung byte, dengan opsi -c( --bytes). (Perhatikan nama opsi yang membingungkan.)

$ printf 'αβγ' | wc -c
6

Tetapi juga dapat menghitung karakter dengan opsi -m( --chars), yang hanya berfungsi:

$ printf 'αβγ' | wc -m
3

Jadi konfigurasi saya tampaknya ok - tetapi ada sesuatu yang istimewa cut.

Mungkin tidak mendukung UTF-8 sama sekali? Tetapi tampaknya mendukung karakter multi-byte, jika tidak maka tidak perlu mendukung -bdan -c.

Jadi, apa yang salah? Dan mengapa?


Pengaturan lokal terlihat tepat untuk utf8, sejauh yang saya tahu:

$ locale
LANG=en_US.UTF-8
LANGUAGE=en_US
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

Input, byte demi byte:

$ printf 'αβγ' | hd 
00000000  ce b1 ce b2 ce b3                                 |......|
00000006

Menarik! Sepertinya -cmenggunakan kode yang sama dengan -b. Apakah Anda sudah melihat kode sumbernya? Mungkin Anda bisa menemukan petunjuk untuk apa -csebenarnya.
— michas

Jawaban:


13

Anda belum mengatakan yang cutAnda gunakan, tetapi karena Anda telah menyebutkan opsi panjang GNU --characterssaya akan menganggap itu salah satunya. Dalam hal ini, perhatikan bagianinfo coreutils 'cut invocation' ini dari :

‘-c character-list’
‘--characters=character-list’

Pilih untuk mencetak hanya karakter dalam posisi yang tercantum dalam daftar karakter. Sama seperti -buntuk saat ini , tetapi internasionalisasi akan mengubahnya.

(penekanan ditambahkan)

Untuk saat ini, GNU cutselalu bekerja dalam hal "karakter" byte tunggal, sehingga perilaku yang Anda lihat diharapkan.


Mendukung opsi -bdan diperlukan oleh POSIX - mereka tidak ditambahkan ke GNU karena memiliki dukungan multi-byte dan mereka bekerja dengan baik, tetapi untuk menghindari memberikan kesalahan pada masukan yang sesuai dengan POSIX. Hal yang sama telah dilakukan dalam beberapa implementasi lain , meskipun tidak FreeBSD dan OS X setidaknya.-ccut-ccut

Ini adalah perilaku bersejarah dari -c. -bbaru ditambahkan untuk mengambil alih peran byte sehingga -cdapat bekerja dengan karakter multi-byte. Mungkin dalam beberapa tahun ini akan berfungsi seperti yang diinginkan secara konsisten, meskipun kemajuannya belum cepat (sudah lebih dari satu dekade sudah). GNU cut bahkan belum mengimplementasikan -nopsi , meskipun itu ortogonal dan dimaksudkan untuk membantu transisi. Ada potensi masalah kompatibilitas dengan skrip lama, yang mungkin menjadi perhatian, meskipun saya tidak tahu pasti apa alasannya.


1
kerja bagus. Anda akan menemukan jenis komentar yang sama di trdokumen GNU juga. dan bahkan tarkecuali saya salah ingat. Saya kira ini adalah proyek besar.
— mikeserv

Apakah ada solusi untuk masalah unicode cut? Misalnya, di mana dimungkinkan untuk mengunduh sumber untuk ditambal cut? Atau akankah lebih mudah menggunakan utilitas lain? ( grepsolusi di bawah ini tidak bekerja dengan baik dengan rentang mis. 5-8,44-49)
— dma_k

lihat artikel 2017 ini, sub-judul "Catatan dan petunjuk acak mengenai upaya yang sedang berjalan untuk menambahkan dukungan multibyte dan unicode di GNU Coreutils" : crashcourse.housegordon.org/coreutils-multibyte-support.html
— myrdd

Anda dapat menemukan beberapa alternatif di cut -csini: superuser.com/questions/506164/…
— myrdd

5

colrm(bagian dari util-linux, harus sudah diinstal pada sebagian besar distribusi) tampaknya menangani internasionalisasi jauh lebih baik:

$ echo 'αβγ' | colrm 3
αβ
$ echo 'αβγ' | colrm 2
α

Waspadalah terhadap penomoran: colrm Nakan menghapus kolom dari N, mencetak karakter hingga N-1.

( kredit )


2

Karena banyak grepimplementasi yang multibyte-sadar, Anda juga dapat menggunakan grep -ountuk mensimulasikan beberapa penggunaan cut -c.

$ echo Τηεοδ29 | grep -o '^..'
Τη
$ echo Τηεοδ29 | egrep -o '^..' | grep -o '.$'
η

Sesuaikan jumlah periode untuk mensimulasikan cutrentang.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.