Eu tenho um arquivo com diversas strings que vêm de um texto formatado em HTML, então elas possuem algumas sequências HTML que não ficam bem em uma interface de console. Aqui está um exemplo:
Text1™
[Text®2]
Text:3
O que estou tentando é remover tudo entre & e ; então o texto pode ser lido novamente, como o seguinte:
Text1
Text2
Text3
Na verdade, estou tentando usar sed para remover os caracteres extras:
sed 's#&*;##g' <file>
O problema é que ele apenas remove o ; das cadeias de texto.
A questão então é: como a expressão regex deve ser codificada para remover a cadeia extra:&#[1-9]+;
Responder1
Sua expressão regular
sed 's#&*;##g' <file>
não faz o que você pensa que faz. O *
caractere é um multiplicador que indica que o caractere anterior é repetido 0 ou mais vezes. O caractere anterior é &
, então isso corresponderia, por exemplo, &&&;
e ;
( &
é escrito 0 vezes antes ;
! Isso é o que corresponde em seus casos de teste), mas não o que você deseja neste caso.
Você precisa especificar "qualquercaractere" antes do multiplicador, que é representado por um único ponto, .
.
$ echo 'Text:3' | sed 's#&.*;##g'
Text3
Esse foi o primeiro problema. O segundo é o conceito da chamada correspondência "ganancioso": sed
verá a primeira &
e depois tentará combinar a maior string possível. Se você tiver várias entidades HTML em uma única linha, isso seria um problema, pois:
$ echo 'Text:3 and some more text å and end' | sed 's#&.*;##g'
Text and end
Se quiser ver uma correção no sed
contexto, você pode procurar o caractere final da entidade correspondendo a qualquer número de "não ;
" antes de um fechamento ;
fazendo:
$ echo 'Text:3 and some more text å and end' | sed 's#&[^;]*;##g'
Text3 and some more text and end
Você ainda terá problemas com usos legítimos do sinal de e comercial ( &
) no texto (bem, &
é o uso "legítimo" real, mas o mundo real nem sempre é tão analisável quanto o ideal) e correspondência demais, mas isso explica por que sed
está se comportando dessa maneira.
Responder2
Não é melhor substituir os códigos pelos caracteres reais?
echo 'Text1™
[Text®2]
Text:3' | perl -C -pe 's/&#([^;]*)/chr$1/eg'
Saída:
Text1™;
[;Text®;2];
Text:;3