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
Volker Siegel
sumber
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.

Michael Homer
sumber
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 )

Skippy le Grand Gourou
sumber
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.

Royce Williams
sumber