sed 文字列に無効な文字が含まれています

sed 文字列に無効な文字が含まれています

次のような見苦しい文字を含むランダムな文字列があります。

このキャラクターは削除する必要があります。ホワイトリストには a-zA-Z0-9 -_*+ß ä ü ö() %@€&= が含まれます。そして空間

これを行う最初のスクリプトは次のとおりです。

regex="[^\-\_\*\+\ß\ä\ö\ü\(\)\%\@\€\&\=\.a-z0-9A-Z\ ]"
replaceChar="_"
echo "testflŒÆ˘ˆı››◊‹ıÓÌˇˆÁÓˆfl̈™ˇÏˆıÍÓÌıÓWÌtest" |sed -e "s/${regex}/${replaceChar}/g"

しかし、これは私の結果です。

test_ŒÆ__ı____ıÓÌ__ÁÓ__Ì___Ï_ıÍÓÌıÓWÌtest

私の$LANG出力

LANG=de_DE.UTF-8

echo "testflŒÆ˘ˆı››◊‹ıÓÌˇˆÁÓˆfl̈™ˇÏˆıÍÓÌıÓWÌtest" | od -c
0000000   t   e   s   t 357 254 202 305 222 303 206 313 230 313 206 304
0000020 261 342 200 272 342 200 272 342 227 212 342 200 271 304 261 303
0000040 223 303 214 313 207 313 206 303 201 303 223 313 206 357 254 202
0000060 303 214 313 206 342 204 242 313 207 303 217 313 206 304 261 303
0000100 215 303 223 303 214 304 261 303 223   W 303 214   t   e   s   t
0000120  \n
0000121

答え1

これにより、正しい正規表現が生成されます。

a="$(printf '%s' {a..z} {A..Z} {0..9} - )"
b="_*+ßäöü()%@€&=."

regex="[^$b$a]"
replaceChar="_"

その後、次のように動作します。

line="testflŒÆ˘ˆı››◊‹ıÓÌˇˆÁÓˆfl̈™ˇÏˆıÍÓÌıÓWÌtest"
echo "$line" | sed -e "s/${regex}/${replaceChar}/g"

test_______________________________W_test

興味深いのは、LANG=Cコマンドが失敗した場合です。次の単純な正規表現を使用しても:

$ (LANG=C; echo "testflŒÆtest" | sed -e "s/[^tesæ]/_/g")
test_____�_test

シンボルが何であるかを確認するには:

$ (LANG=C; echo "testflŒÆtest" | sed -e "s/[^tesæ]/_/g")|od -An -tcx1
   t   e   s   t   _   _   _   _   _ 303   _   t   e   s   t  \n
  74  65  73  74  5f  5f  5f  5f  5f  c3  5f  74  65  73  74  0a

つまり、303です。長い文字列についても繰り返されます。たぶんそれがあなたが見ているものかもしれません。

答え2

コレクションがよくわからない場合(またはその補足)、私は通常否定、特に範囲を信じていません。私はあなたの醜い文字列のほとんどの文字を知らず、それがどこから来たのか、私のコンピュータが興味を持っているのかわかりません。私は他の文字のいくつかを認識し、何かを削除する方法を知っていますが、すべての醜い文字が少なくとも有効な文字である限り。

alnum=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
sed -e's|.|&\n|g'     -e'# this opens up the string' \
    -e"s|\([-$alnum*_+ßäüö ()%&@=.$€]\)\{0,1\}.\{0,1\}\n|\1_|g" \
<<""
testflŒÆ˘ˆı››◊‹ıÓÌˇˆÁÓˆfl̈™ˇÏˆıÍÓÌıÓWÌtest

testWtest

^そうですか?

したがって、文字列を\n文字ごとに1行に分割し、左から右に一度に1文字ずつスキャンします。これを行うときは、各文字に対して2つの操作のうちの1つを実行します。つまり、ホワイトリスト内の文字の1つをその文字の0〜1項目に置き換えるか、別の文字の0〜1項目を削除します。どちらの場合も、末尾の改行文字も削除されます。

下線を使用すると、何をしているのかをより簡単に知ることができるようです_(おそらくそれでそれを含めたでしょう):

sed -e's|.|&\n|g'     -e'# this opens up the string' \
    -e"s|\([-$alnum*_+ßäüö ()%&@=.$€]\)\{0,1\}.\{0,1\}\n|\1_|g" \
<<""
    testflŒÆ˘ˆı››◊‹ıÓÌˇˆÁÓˆfl̈™ˇÏˆıÍÓÌıÓWÌtest

 _ _ _ _t_e_s_t________________________________W__t_e_s_t_

sed交換可能です。無効- 長さ文字列。削除しても大丈夫ですが、sed受け入れたり保管しても大丈夫です。それでも。ああ、スペースですよね。(Markdownコードブロックのインデント用)空間だ。

私が\newlineを使用している理由の1つは、パターン空間で無効なバイト列に何が起こるかに関するものです。実際の文字と同じでない場合、一致せずに.失敗/^.*$/します。改行の場合、無効なバイトシーケンスの後の文字が.最初に一致すると、次のようになります。

sed    '/^.*$/!{/\n/D;}'

...もう過ぎます。(しかし、GNUではありませんsed。最初に確認しなければなりませんでした。sed以前はASTを使用していました。面倒ではありませんでした。)。 GNUを使用してパターン領域全体を適用しますsed zz

関連情報