Sed によるファイル形式の変更を回避するにはどうすればよいでしょうか?

Sed によるファイル形式の変更を回避するにはどうすればよいでしょうか?

sed ファイルを使用してファイルを前処理しようとしましたが、sed からの出力によって形式が変わるようです。これを回避するにはどうすればよいですか?

file A.txt
A.txt UTF-8 Unicode English text, with very long lines

sed -f process.sed < A.txt > B.txt

head -2 process.sed
#!/bin/sed -f
s/[‘’"“”•·・、。《》™®\.★☆]\\[a-z\-]\+ //g

file B.txt
Non-ISO extended-ASCII English text, with very long lines, with LF, NEL line terminators

B.txt は UTF-8 でエンコードされていないため、以下の処理は実行できません。

vim B.txt
è·¯æ<98><93>æ<96>¯ Âç½<97>å¾·é<87><8c>æ ¼æ<96>¯ //è·¯æ<98><93>æ<96>¯Â·ç½<97>å¾·é<87><8c>æ ¼æ<96>¯ ]

答え1

問題は、sed の正規表現エンジンが入力ファイルも一致も[…]Unicode 文字のリストとして見ないことです。代わりに、それぞれを複数の独立したバイトとして見ます。たとえば、 を3 バイトとして見て\xe2 \x80 \xa2、それぞれを と個別に一致させようとします[ \xe2 \x80 \x98 \xe2 \x80 \x99 \x22 \xe2 \x80 ... ]

したがって、投稿で示した例では、正規表現は各句読点文字の最後のバイトのみを一致させて削除しますが、他の 2 つはそのまま残します。これが無効な (UTF-8 以外の) 出力ファイルを生成する原因です。

GNU sed(4.5でテスト済み)では、システムロケール($LANG または少なくとも $LC_CTYPE 環境変数) が UTF-8 互換のロケールに設定されています。例:

$ エクスポートLANG='C'
$ echo ''test' “test”' | sed 's/[“”•]/X/g'
XX�テストXX� XXXテストXXX
$ echo '•_test' | sed 's/[•‡]_/X_/'
��X_テスト

$ エクスポート LANG='en_US.UTF-8'
$ echo ''test' “test”' | sed 's/[“”•]/X/g'
'テスト' XtestX
$ echo '•_test' | sed 's/[•‡]_/X_/'
X_テスト

(ロケール言語は関係ありません。どれでもUTF-8 ロケールが機能します。

これがうまくいかない場合は、[…]完全に回避して\(…\|…\|…\)(または(…|…|…)sed -r) を使用してください。これは複数文字の代替手段であり、それらの文字が最終的にどのように解釈されるかに関係なく機能します。

$ エクスポートLANG='C'
$ echo ''test' “test”' | sed 's/\(“\|”\|•\)/X/g'
'テスト' XtestX
$ echo '•_test' | sed 's/\(•\|‡\)_/X_/'
X_テスト

関連情報