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每个字符一行,然后从左到右一次扫描一个字符。这样做时,它会为每个字符执行以下两件事之一 - 要么用 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 代码块缩进)是空格。

我使用\newlines 的原因之一与模式空间中无效字节序列所发生的情况有关。如果它不等于实际字符,.则不匹配,并且/^.*$/会失败。对于换行符,如果坏字节序列后面的任何字符.首先成功匹配,则:

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

...会过去的(但不是 GNU sed- 我应该先检查一下。我sed之前使用的是 AST - 这并不麻烦)。使用 GNUsed zzap 整个模式空间。

相关内容