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


15

このコマンドに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番目のバイトです。
したがって、代わりに2番目の文字を見てみましょう。

$ 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

面白い!と-c同じコードを使用しているようです-b。ソースコードを見ましたか?たぶん、あなた-cは実際に何のためにあるのかヒントを見つけることができます。
michas 14年

回答:


13

どちらcutを使用しているのかはまだ説明していませんが、GNUの長いオプションについて説明したので、それがそのオプションである--charactersと仮定します。その場合、次の箇所からinfo coreutils 'cut invocation'注意してください。

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

文字リストにリストされている位置の文字のみを印刷する場合に選択します。今と同じ-bですが、国際化がそれを変えます。

(強調を追加)

現時点では、GNUはcut常にシングルバイトの「文字」の観点から機能するため、表示される動作は予期されたものです。


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

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


1
よくできました。GNUのtrドキュメントにも同じ種類のコメントがあります。そして、さえtar私misrememberない限り。大きなプロジェクトだと思います。
mikeserv 14年

unicode probelmの回避策はありますcutか?たとえば、パッチを適用したソースをどこでダウンロードできますcutか?または、別のユーティリティを使用する方が簡単ですか?(grep以下のソリューションは範囲ではスムーズに機能しません。例5-8,44-49
-dma_k

参照この2017年の記事、副題「進行GNUのCoreutilsにマルチバイトおよびUnicodeのサポートを追加するための努力についてのランダムノートとポインタ」crashcourse.housegordon.org/coreutils-multibyte-support.html
myrdd

あなたは、いくつかの選択肢を見つけることができますcut -c:ここsuperuser.com/questions/506164/...
myrdd

5

colrm(の一部はutil-linux、ほとんどのディストリビューションにすでにインストールされているはずです)国際化をはるかにうまく処理しているようです:

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

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

クレジット


2

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.