UTF-8 ile `cut -c` (` --characters ') kullanılamaz mı?


15

Komutun cut, seçeneğe -csahip baytlar yerine karakterler üzerinde çalışma seçeneği vardır -b. Ancak bu, en_US.UTF-8yerel olarak çalışmıyor gibi görünüyor :

İkinci bayt, ikinci ASCII karakterini verir (UTF-8'de aynı şekilde kodlanır):

$ printf 'ABC' | cut -b 2          
B

ancak UTF-8 yerel ayarında üç Yunanca olmayan ASCII olmayan karakterin ikincisini vermez:

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

Bu iyi - ikinci bayt .
Bunun yerine ikinci karaktere bakıyoruz :

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

Kırık görünüyor.
Bazı deneylerde, aralığın 3-4ikinci karakteri gösterdiği ortaya çıkıyor :

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

Ancak bu, 3 ila 4 arasındaki baytlarla aynıdır:

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

Yani UTF-8 için -cfazla değildir -b.

Yerel ayar UTF-8 için doğru değil, ancak karşılaştırma, wcbeklendiği gibi çalışır;
Genellikle -c( --bytes) seçeneği ile bayt saymak için kullanılır . (Kafa karıştırıcı seçenek adlarına dikkat edin.)

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

Ancak, şu şekilde çalışan seçenek -m( --chars) ile karakterleri de sayabilir :

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

Bu yüzden yapılandırmam iyi görünüyor - ama özel bir şey var cut.

Belki de UTF-8'i desteklemiyor? Ama aksi takdirde desteklemeye gerek olmazdı, çok baytlık karakterleri desteklemek için görünüyor -bve -c.

Yani ne yanlış? Ve neden?


Yerel ayar, söyleyebildiğim kadarıyla utf8 için doğru görünüyor:

$ 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=

Girdi, bayt bayt:

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

İlginç! Görünüşe göre -caynı kodu kullanıyor -b. Kaynak koduna baktınız mı? Belki de -caslında bunun için bir ipucu bulabilirsiniz .
michas

Yanıtlar:


13

Hangisini cutkullandığınızı söylemediniz , ancak GNU uzun seçeneğinden bahsettiğinizden beri --charactersbunun olduğunu varsayıyorum. Bu durumda, şu pasajainfo coreutils 'cut invocation' dikkat edin :

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

Yalnızca karakter listesinde listelenen konumlardaki karakterleri yazdırmak için seçin. Şimdilik aynı-b , ancak uluslararasılaşma bunu değiştirecek.

(vurgu eklendi)

Şu an için GNU cuther zaman tek baytlık "karakterler" olarak çalışır, bu nedenle gördüğünüz davranış beklenir.


POSIX için -bhem -cseçenekleri hem de seçenekleri desteklemek gerekir - cutçoklu bayt desteği olduğu ve düzgün çalıştıkları için GNU'ya eklenmediler , ancak POSIX uyumlu girişte hata vermemek için. Aynı -cşey en azından FreeBSD ve OS X'lerdecut olmasa da diğer bazı uygulamalarda da yapılmıştır .

Bu tarihi davranış arasında -c. çok baytlı karakterlerle çalışabilmek -biçin bayt rolünü üstlenmek üzere yeni eklendi -c. Belki birkaç yıl içinde sürekli olarak istenen şekilde çalışacaktır, ancak ilerleme tam olarak hızlı olmamasına rağmen (zaten on yıldan fazladır). GNU , dikey ve geçişe yardımcı olması amaçlanmış olsa bile cut , -nseçeneği henüz uygulamıyor . Nedenin ne olduğunu kesin olarak bilmememe rağmen, eski betiklerle ilgili olası uyum sorunları vardır.


1
iyi iş. GNU trbelgelerinde de aynı türden yorumlar bulacaksınız . ve taryanlış hatırlamıyorsam bile . Bence bu büyük bir proje.
mikeserv

Unicode probelm için herhangi bir geçici çözüm var mı cut? Örneğin, yamalı kaynakların nereden indirilebileceği cut? Yoksa başka bir yardımcı program kullanmak daha mı kolay olur? ( grepaşağıdaki çözüm aralıklarla düzgün çalışmaz örneğin 5-8,44-49)
dma_k

"GNU Coreutils'te çok baytlı ve unicode desteği ekleme çabalarına ilişkin rastgele notlar ve işaretçiler" başlıklı bu makaleye bakın :: crashcourse.housegordon.org/coreutils-multibyte-support.html
myrdd

cut -cburada bazı alternatifler bulabilirsiniz : superuser.com/questions/506164/…
myrdd

5

colrm(bir kısmı, util-linuxçoğu dağıtımda zaten kurulu olmalıdır) uluslararasılaşmayı çok daha iyi ele alıyor gibi görünüyor:

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

Numaralandırmaya dikkat edin: en fazla karakter yazdıracak şekilde colrm Nsütunları kaldıracak .NN-1

( kredi )


2

Birçok grepuygulama çok baytlı olduğundan, grep -obazı kullanımlarını simüle etmek için de kullanabilirsiniz cut -c.

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

cutAralıkları simüle etmek için nokta sayısını ayarlayın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.