encontra uma string específica e apaga toda a estrutura

3

Eu tenho um arquivo vertical onde cada palavra (token) está na linha separada em 4 colunas. Há também metastructures <doc> , <s> , ... Os documentos são os seguintes:

<doc name="sth" url="http">
<p>
<s>
Here   here   k1gInSc1   here
is   be   k1gMnPc2   be
a  a   k2eAgMnPc1d1   a
sentence   sentence   k1gMnPc1   sentence
<g/>
.       .       kIx.
</s>
</p>
</doc>

o problema é que às vezes há uma codificação incorreta com caracteres como Ă ou Ä na primeira coluna, por exemplo

<doc name="sth" url="http">
<p>
<s>
Here   here   k1gInSc1   here
is   be   k1gMnPc2   be
Ă  Ă   k?   Ă
sentence   sentence   k1gMnPc1   sentence
<g/>
.       .       kIx.
</s>
</p>
</doc>

Eu precisaria encontrar esses caracteres e excluir toda a estrutura do documento. Então, se eu encontrar É em uma linha, eu preciso deletar todo o conteúdo entre <doc...> all lines </doc> .

Meu arquivo tem um bilhão de linhas e alguns milhares de linhas contêm caracteres codificados errados.

Eu usei o grep para encontrar personagens ruins:

xzcat file.vert.xz | grep -i "Ă\|Ĺ\|ľ\|ş\|Ä" > file_bad_characters.txt

Como posso detectar esses caracteres e excluir não apenas a linha, mas todo o texto entre <doc> estruturas.

    
por Rodrigo 03.03.2017 / 13:36

2 respostas

2

A maneira correta de fazer isso é usar um analisador XML adequado. No entanto, nesse caso, o seguinte pode funcionar como uma solução alternativa:

  1. Remova todas as linhas em branco do arquivo:

    sed -i '/^\s*$/d' file
    
  2. Adicione uma linha em branco antes de cada <doc> :

    sed -i 's/<doc/\n\n<doc/' file 
    
  3. "modo de parágrafo" do User Perl, onde "linhas" são definidas como "parágrafos" (seções de texto precedidas por uma linha vazia):

    perl -00 -ne 'print unless /[ĂĹľşÄ]/' file > newfile
    

    Ou para fazer as substituições no arquivo original:

    perl -i.bak -00 -ne 'print unless /[ĂĹľşÄ]/' file
    

IMPORTANTE : isso pressupõe um arquivo bem estruturado em que tudo está dentro de tags <doc... .

    
por 03.03.2017 / 13:54
2

Isso não é algo que você possa fazer com apenas o grep, receio; isso requer que você retenha algum contexto sobre as linhas que o grep não pode fornecer. No entanto, existem várias outras linguagens que podem fazer isso; aqui está um exemplo com awk :

awk '/<doc>/ {text=""; output=1}
     /Ă|Ĺ|ľ|ş|Ä/{output=0}
     {text = text $0 "\n"}
     /<\/doc>/ {if(output==1){printf "%s", text}}"

Isso cria um buffer chamado text quando vemos um token <doc> na entrada e define um sinalizador para sinalizar que queremos ver o texto impresso; esse sinalizador é limpo quando os caracteres proibidos são encontrados. Quando encontramos o token </doc> , verificamos se o sinalizador ainda está definido; Nesse caso, exibimos o buffer. Finalmente, cada linha é adicionada ao nosso buffer, independentemente de o sinalizador estar ou não definido.

    
por 03.03.2017 / 13:56