trにASCII以外の(Unicode)文字を認識させる方法は?

trにASCII以外の(Unicode)文字を認識させる方法は?

ファイル(UTF-8)からいくつかの文字を削除しようとしています。trこの目的のために私が使用するもの:

tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat 

ファイルには一部の外国文字(「Латвийская」や「àé」など)が含まれています。trそれらを理解していないようです:それはアルファではないものとして扱い、削除します。

いくつかのロケール設定を変更してみました。

LC_CTYPE=C LC_COLLATE=C tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
LC_CTYPE=ru_RU.UTF-8 LC_COLLATE=C tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
LC_CTYPE=ru_RU.UTF-8 LC_COLLATE=ru_RU.UTF-8 tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat

残念ながら、これらのどれも機能しません。

Unicodeをどのように理解できますかtr

答え1

これは知られている(12サム456)GNU実装の制限tr

サポートしていないわけではない。外国の、英語ではない、またはASCII以外の文字ですが、マルチバイト文字はサポートされていません。

iso8859-5(文字ごとに1バイト)文字セットとして書き込む場合(ロケールがその文字セットを使用している場合)、これらのキリル文字は正しく処理されますが、問題はASCIIではなくUTF-8文字を使用することです。 2バイト以上でエンコードされます。

GNUは計画(望むより返品)この問題を解決するための作業は進行中ですが、まだ実装されていません。

FreeBSDやSolarisにはtrこの問題はありません。


一方、ほとんどのユースケースでは、trマルチバイト文字をサポートするGNU sedまたはGNU awkを使用できます。

たとえば、

tr -cs '[[:alpha:][:space:]]' ' '

次のように書くことができます:

gsed -E 's/( |[^[:space:][:alpha:]])+/ /'

または:

gawk -v RS='( |[^[:space:][:alpha:]])+' '{printf "%s", sep $0; sep=" "}'

小文字と大文字()の間をtr '[:upper:]' '[:lower:]'変換するには:

gsed 's/[[:upper:]]/\l&/g'

(数字ではなくl小文字です。)L1

または:

gawk '{print tolower($0)}'

移植性のためのperl別のオプションがあります。

perl -Mopen=locale -pe 's/([^[:space:][:alpha:]]| )+/ /g'
perl -Mopen=locale -pe '$_=lc$_'

データがシングルバイト文字セットとして表現できることがわかっている場合は、その文字セットとして扱うことができます。

(export LC_ALL=ru_RU.iso88595
 iconv -f utf-8 |
   tr -cs '[:alpha:][:space:]' ' ' |
   iconv -t utf-8) < Russian-file.utf8

答え2

GNU sedを使用してください(LANG例:適切な環境変数を含むen_US.UTF-8)。

% sed 'y/123/abc/; y/āōī/456/' <<< test123ingmāōī
testabcingm456

関連情報