sed string com caracteres incorretos

4

Eu tenho uma string aleatória com caracteres feios nela: ˇÌ Ì Ì ‹‹ Í Í ‹‹ ‹

Esses caracteres precisam ser eliminados. A Whitelist consiste em: a-zA-Z0-9 -_ * + ß ä ü ö ()% @ € & =. e espaço

Meu primeiro script para fazer isso:

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

Mas esta é minha saída:

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

Minha saída para $ 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
    
por Thomas Ott 07.12.2015 / 17:25

2 respostas

2

Isso criará o regex correto:

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

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

Então isso funcionará:

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

test_______________________________W_test

É interessante notar que se LANG=C o comando falhará. Mesmo com um regex tão simples como isto:

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

Para ver qual é o número do caractere:

$ (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

Ou seja: 303. Isso também se repete para strings mais longas. Talvez seja o que você viu.

    
por 08.12.2015 / 02:55
0

Se eu não conheço muito bem o conjunto (ou seu complemento) , geralmente não confio em negação - especialmente em intervalos. Eu não sei a primeira coisa sobre a maioria desses personagens em sua string feia, ou de onde eles vieram, ou se meu computador se importa. Eu conheço alguns dos outros, e sei como remover qualquer coisa, mas - desde que todos os personagens feios sejam pelo menos caracteres válidos.

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

^ isso é certo, certo?

Então, ele divide a string em um \n ewline por caractere e, em seguida, verifica a string um caractere por vez, da esquerda para a direita. Ao fazê-lo, ele fará uma de duas coisas para cada uma delas: substituirá um dos seus caracteres na lista de desbloqueio por 0 ou 1 ocorrências de si mesmo ou removerá 0 ou 1 ocorrências de algum outro caractere. Em ambos os casos, também remove o delimitador de nova linha à direita.

Acho mais fácil ver o que acontece com _ underscores - (que é provavelmente o motivo pelo qual você os incluiu) :

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

Isso é o que o sed fará com a substituição de uma cadeia de caracteres de comprimento nula . Remover é bom - mas sed pode pegar ou deixar, e irá . Ah, os espaços, bem, eu apenas copiei e colei no terminal e então os quatro personagens principais (para o recuo do bloco de código Markdown) eram espaços.

Um motivo pelo qual eu uso o \n ewlines tem a ver com o que acontece com uma seqüência de bytes inválida no espaço padrão. Se não resultar em um caractere real, . não corresponderá e /^.*$/ falhará. Com as novas linhas, se algum caractere seguindo a sequência de byte ruim conseguir corresponder a . em primeiro lugar, então:

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

... funcionará depois (mas não com um GNU sed - acho que eu deveria ter verificado primeiro. Eu estava usando o AST sed anterior - o que não é um problema) . Com% GNUsed z irá z ap todo o espaço padrão.

    
por 08.12.2015 / 02:22