sedが「間違った」文字を見つけたときに解析を続けるように強制する方法は?

sedが「間違った」文字を見つけたときに解析を続けるように強制する方法は?

誤ってエンコードされた文字列を含む大きなプレイリスト.pls(再生ソフトウェアで生成)があります。これがバグなのかプラグインの一つなのかdeadbeefはわかりませんが。deadbeefsed

しかし、これは一見より簡単ですsed邪魔する文字が見つかるとすぐに「無効」と見なされる文字を解析します。

$ cat archives.pls | grep --perl-regexp Lika.*rar.*02
rar:///home/andy/audio_compressed/world/ru/Lika Star - Ya (RUS 2001).rar:2001- �/02 ���.mp3

変更されていない元の行です。それでは、パスを抽出して試してみましょうsed。 (注:これはディレクトリツリーで「死んだ」オーディオファイル、つまり存在しなくなったファイルを確認するために完了したいスクリプトです。)

 $ cat archives.pls | grep --perl-regexp Lika.*rar.*02 | sed -e 's/^\(zip\|rar\|7z\):\/\///' -e 's/\(\.\(zip\|rar\|7z\)\):.*/\1/'
 /home/andy/audio_compressed/world/ru/Lika Star - Ya (RUS 2001).rar�/02 ���.mp3

ああ。これは明らかに動作しません。正規表現ははい絶対に正確です(いわゆる「有効な」文字で正しく機能することが証明されるため)。実際、コロンから「2001-」まで空白に解析した後、突然無効な文字で停止することを意味するrar�Originalの略語に由来しました。それでも質問が残っています。エンコーディングが何であるかを無視して、とにかく解析するとどうでしょうか?私の言葉では、私たちは「rar」の後ろのコロンの後ろのすべての内容を切り取りたいので、仮定するのは安全でなければなりません。rar:2001- �sedsed.* する 絶対に代表的ですどの特徴?

cut注:答えに「エレガントに見える」ソリューションを使用しないでください。あった、そうだった。代わりに、私たちはUNIX型のオペレーティングシステムを使用しており、元の ":wumpscut:"または同様のスペルを使用したアーティストに関連する奇妙なファイル名を法的に使用することができることを考慮することをお勧めします。つまり、途中で別のコロンがある可能性があるため、後で最初に会うコロンを静的に切り取ることは良い考えではありません(zip|rar|7z)://

答え1

Goldilocksがすでに上記したように、UTF-8はマルチバイト可変幅エンコーディング。各文字は最大4バイトで構成できます。無効なバイトの後に最大にすることができます希望次のバイトは新しい文字を開始できます。

sedバイトではなく文字を一致させてください。無効なバイトは文字ではなく、.一致する唯一の文字なので、一致しないため、結果は絶対に正確です。

ファイルがどのエンコーディングを使用しているかを調べる必要があります。 (このfileコマンドはこれを行うのに役立ちます。)環境変数を正しい値に設定すると、期待どおりに機能するのLANGに十分です。sedあなたの場合、おそらくLANG=C十分です。

答え2

環境変数をLANGUTF-8でエンコードされた文字列(LANG='en_US.UTF-8'Mac OS X 10.6.8など)に設定すると、質問で述べたようにLANG='C'GNU 4.2.1の解析が停止します。一方、GNU 4.2.2はうまく動作します。sedsed

私に役立つもう1つの修正(Mac OS X 10.6.8)は、正規表現部分を次のよう:.*に置き換えることでした::\([^[:print:]]\|[[:print:]]\)*(POSIX文字クラス)。

echo $'rar:///home/andy/audio_compressed/world/ru/Lika Star - Ya (RUS 2001).rar:2001- \357\277\275/02 \357\277\275\357\277\275\357\277\275.mp3' > archives.pls

(
export LANG='C'
#locale charmap
cat archives.pls | grep --perl-regexp 'Lika.*rar.*02'
cat archives.pls | grep --perl-regexp 'Lika.*rar.*02' | gsed -e 's/^\(zip\|rar\|7z\):\/\///' -e 's/\(\.\(zip\|rar\|7z\)\):.*/\1/'    # GNU sed 4.2.1
cat archives.pls | grep --perl-regexp 'Lika.*rar.*02' | gnused -e 's/^\(zip\|rar\|7z\):\/\///' -e 's/\(\.\(zip\|rar\|7z\)\):.*/\1/'  # GNU sed 4.2.2
cat archives.pls | grep --perl-regexp 'Lika.*rar.*02' | gsed -e 's/^\(zip\|rar\|7z\):\/\///' -e 's/\(\.\(zip\|rar\|7z\)\):\([^[:print:]]\|[[:print:]]\)*/\1/'
)


# output:
# rar:///home/andy/audio_compressed/world/ru/Lika Star - Ya (RUS 2001).rar:2001- �/02 ���.mp3
# /home/andy/audio_compressed/world/ru/Lika Star - Ya (RUS 2001).rar�/02 ���.mp3
# /home/andy/audio_compressed/world/ru/Lika Star - Ya (RUS 2001).rar
# /home/andy/audio_compressed/world/ru/Lika Star - Ya (RUS 2001).rar

#--------------

(
export LANG='en_US.UTF-8'
#locale charmap
cat archives.pls | grep --perl-regexp 'Lika.*rar.*02'
cat archives.pls | grep --perl-regexp 'Lika.*rar.*02' | gsed -e 's/^\(zip\|rar\|7z\):\/\///' -e 's/\(\.\(zip\|rar\|7z\)\):.*/\1/'    # GNU sed 4.2.1
cat archives.pls | grep --perl-regexp 'Lika.*rar.*02' | gnused -e 's/^\(zip\|rar\|7z\):\/\///' -e 's/\(\.\(zip\|rar\|7z\)\):.*/\1/'  # GNU sed 4.2.2
cat archives.pls | grep --perl-regexp 'Lika.*rar.*02' | gsed -e 's/^\(zip\|rar\|7z\):\/\///' -e 's/\(\.\(zip\|rar\|7z\)\):\([^[:print:]]\|[[:print:]]\)*/\1/'
)

# output:
# rar:///home/andy/audio_compressed/world/ru/Lika Star - Ya (RUS 2001).rar:2001- �/02 ���.mp3
# /home/andy/audio_compressed/world/ru/Lika Star - Ya (RUS 2001).rar
# /home/andy/audio_compressed/world/ru/Lika Star - Ya (RUS 2001).rar
# /home/andy/audio_compressed/world/ru/Lika Star - Ya (RUS 2001).rar

関連情報