web-dev-qa-db-ja.com

UTF-8で `cut -c`(` --characters`)を使用できませんか?

コマンドcutには、オプション-cを使用したバイトの代わりに、文字を処理するためのオプション-bがあります。しかし、それはen_US.UTF-8ロケールでは機能しないようです。

2番目のバイトは、2番目のASCII文字(UTF-8でもまったく同じようにエンコードされます)を提供します)を示します。

$ printf 'ABC' | cut -b 2          
B

ただし、UTF-8ロケールでは3つのギリシャ語の非ASCII文字のうち2番目の文字は提供されません。

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

それは大丈夫です-それは2番目のbyteです。
代わりに、2番目のcharacterを調べます。

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

壊れているようです。
いくつかの実験により、範囲3-4は2番目の文字を示していることがわかります。

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

しかし、それはバイト3から4と同じです。

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

そのため、UTF-8では-c-bを超えません。

ロケールの設定はUTF-8では正しくないと思いますが、比較すると、wcは期待どおりに機能します。
オプション-c--bytes)を使用して、バイトをカウントするためによく使用されます。 (紛らわしいオプション名に注意してください。)

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

ただし、オプション-m--chars)を使用して文字をカウントすることもできます。

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

だから私の設定は問題ないようですが、cutについて特別なものがあります。

多分それはまったくUTF-8をサポートしていませんか?ただし、マルチバイト文字をサポートしているようですが、そうでない場合は、-bおよび-cをサポートする必要はありません。

それで、何が悪いのですか?そしてなぜですか?


ロケール設定は、私が知る限り、utf8に適しています。

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

バイト単位の入力:

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

使用しているcutはまだ言っていませんが、GNU長いオプション--charactersと言ったので、これがそうだと思います。その場合、これに注意してください info coreutils 'cut invocation'からの通路

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

文字リストにリストされた位置にある文字のみを印刷する場合に選択します。 現時点では-bと同じですが、国際化により変更されます。

(強調を追加)

現時点では、GNU cutは常にシングルバイトの「文字」で機能するため、期待どおりの動作が期待できます。


-bオプションと-cオプションの両方をサポートすることは POSIXで必須 —これらはGNU cutに追加されなかったため、マルチバイトをサポートし、適切に機能しましたが、POSIX準拠の入力でエラーが発生するのを回避するために、同じ-cが他の一部のcut実装で行われていますが、そうではありません FreeBSDOS X は少なくとも。

これは-cの-​​ historic behaviour です。 -bがマルチバイト文字を処理できるように、バイトの役割を引き継ぐために-cが新たに追加されました。たぶん数年で、それは期待どおりに一貫して機能しますが、進歩は正確には迅速ではありません(すでに10年以上経過しています)。 GNU cut-nオプションも実装されていません ですが、これは直交しており、移行を支援することを目的としていますが、古いスクリプトとの潜在的な互換性の問題であり、懸念される可能性がありますが、その理由は明確にはわかりません。

13
Michael Homer

colrmutil-linuxの一部であり、ほとんどのディストリビューションにすでにインストールされているはずです)は、国際化をより適切に処理するようです:

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

番号付けに注意してください:colrm NNから列を削除し、N-1までの文字を印刷します。

クレジット

多くのgrep実装はマルチバイトに対応しているため、grep -oを使用してcut -cの一部の使用をシミュレートすることもできます。

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

期間数を調整してcut範囲をシミュレートします。

3
Royce Williams