perlとsedの印刷できない文字を置き換える


11

ファイル内の一部の印刷できない文字をスペースで置き換える必要があります。

具体的には、(TAB)、(改行)、(CR)を除く、から0x00までのすべての文字0x1F0x090x0A0x0D

今までは0x00キャラクターを入れ替えるだけでした。私の以前のOSはAIX(GNUコマンドなし)だったので、使用できませんsed(まあ、使用できますが、いくつかの制限がありました)。だから、私はを使用して次のコマンドを見つけましたperl、それは期待通りに機能しました:

perl -p -e 's/\x0/ /g' $FILE_IN > $FILE_OUT 

現在はLinuxを使用しているので、sedコマンドを使用できると期待していました。

私の質問:

  • このコマンドはそれらの文字を置き換えるのに適切ですか?私が試しました、そしてそれはうまくいくようですが、私は確かめたいです:

    perl -p -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT  
  • perl -pとして動作すると思ったsed。それでは、なぜ前のコマンドは機能し(少なくとも失敗しません)、次のコマンドは機能しませんか?

    sed -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT   

    それは私に伝えます:

    sed:-e expression#1、char 34:無効な照合文字


perl -pstdin希望する操作を行った後の最終製品を印刷します。この場合、それは単なる交換です。sedの正規表現はとは異なる場合がありperlます。
sdkks 2017

回答:


11

これは、の典型的な仕事ですtr

LC_ALL=C tr '\0-\10\13\14\16-\37' '[ *]' < in > out

あなたの場合、sedそれらの範囲が意味をなさないロケールにいるので、それは動作しません。文字ではなくバイト値を処理したい場合、およびそれらのバイトの数値に基づいて順序が決まる場合は、Cロケール使用することをお勧めします。あなたのコードはLC_ALL=CGNU で動作しますsedが、sed(それだけでなくperl)を使用すること\xXXはここでは少しやりすぎです(そしてsed、このtrアプローチがPOSIXである間、それらは実装間で移植可能ではありません)。

また、印刷可能な文字が何であるかというロケールの考えを信頼することもできます。

tr -c '[:print:]\t\r\n' '[ *]'

しかし、GNU tr(通常、Linuxベースのシステムで見られる)では、文字がシングルバイト(したがって、通常はUTF-8ではない)のロケールでのみ機能します。

Cロケールでは、DEL(0x7f)と上記のすべてのバイト値(ASCIIではない)も除外されます。

UTF-8ロケールでsedは、GNU trに問題がないGNU を使用できます。

sed 's/[^[:print:]\r\t]/ /g' < in > out

(これらは標準\r\tはないことに注意してください。環境にあるsed場合、GNU はそれらを認識しませんPOSIXLY_CORRECT(バックスラッシュとして扱い、rとtはPOSIXが要求するセットの一部です))。

有効な文字を形成しないバイトがあっても変換しません。


trコマンドの意味を理解しています。私(多かれ少なかれ)何LC_ALL = Cが何であるかを理解していますが、全部ではありません。それでもtr -dこれらの文字は削除されますが、スペースで置き換えたいと思います。タイトルが間違っていました。@don_crisstiが変更されたとき、私は気づきました。
アルバート

@アルバート、ごめんなさい。追加した編集とリンクを参照してください。
ステファンChazelas

エンコードについてはわかりません。そのファイルは、EBCDICエンコーディングを使用するHOST環境から取得され、を使用してLinuxに転送されXCOMます。たとえば、のような非ASCII文字Éは(を使用してod -xa)としてコード化される0xC9ので、それはそうなると思いますISO-8859-1
アルバート

@アルバート、おそらく。を使用locale -aして、システムに文字セットとしてiso8859-1を使用するロケールがあるかどうかを確認しLC_CTYPE=<that-locale> tr ...[:print:]...、そのロケールで印刷不可を変換するために使用できます。または、iconvを使用して、これらのファイルをロケールの文字セットに変換できます。
ステファンChazelas

私のロケールの文字セットがに設定されてLC_ALL=en_US.iso88591いるので、それは必要ないと思います。そのため、コマンド(tr -c '[:print:]\t\r\n' '[ *]')は、ロケールの変更やファイルの変換を行わなくても完全に機能します。どうもありがとう。
アルバート

0

印刷できない文字が含まれている可能性のあるコンテンツを含むlibnotifyを介して通知を送信しようとしました。既存の解決策は私にとってはうまくいきませんでした(作品を使用して文字のホワイトリストを使用しましたtrが、マルチバイト文字は取り除きました)。

workedテストに合格したときの動作は次のとおりです。

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