grep regex. * não combinando tudo

1

Recentemente, comecei a usar ferramentas como grep , wc , cat , etc. porque tenho que lidar com alguns arquivos CSV muito grandes (> 10 GB) que não são bem delimitados corretamente ( por exemplo, ter ocorrências do caractere delimitador dentro de alguns dos campos.

No meu trabalho com um desses arquivos, executei o seguinte comando no processo de tentar descobrir uma maneira de identificar corretamente quais instâncias de ; são um delimitador e substituí-las por algum outro caractere:

grep -v -n --text "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].*[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].*[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].*[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]" < Transactions.csv

O regex provavelmente pode ser feito muito melhor, mas de qualquer maneira; O que é surpreendente é que, entre outros, o código acima produz a seguinte linha:

12345678:2016-10-25;12345678912345;2016-10-25;gobbledegook �IDNR: 69 ;12345.67;.00;2003-09-05;12345678;2003-09-03;stuff stuff         ;12345 fgadfkjgbsdkb;12/3/45678/9

(como isso foi realmente dados de transação, eu mudei a maioria dos valores dos campos, exceto para o ofender ) Talvez eu esteja sendo bobo, mas por que a regex acima não combina com essa linha? Parece que o regex .* de alguma forma não corresponde ao caractere por algum motivo.

Eu suspeito que o arquivo seja salvo usando a codificação UTF-16, se isso fizer alguma diferença.

Editar: Obrigado ao @exore pela resposta. Como se viu, meu arquivo foi codificado em ISO-8859-15, que eu pude entender por grep ping das linhas contendo caracteres especiais, que eram relativamente poucos, em um arquivo e abrindo isso no gedit. Eu então usei iconv para convertê-lo em utf8, após o que funcionou bem!

    
por Liam Baker 15.11.2016 / 17:02

1 resposta

1

Este é um problema típico de codificação de caracteres. . significa qualquer caractere. Mas qual sequência de bytes é um caractere legal é uma questão de codificação. Lidar com texto sem o conhecimento da codificação é uma falha segura. Seu comando grep provavelmente espera uma string codificada em UTF-8. UTF-8 é uma codificação multibyte, o que significa que alguns caracteres são representados por múltiplos bytes. No entanto, nem todas as seqüências de bytes são válidas. Veja, por exemplo, o artigo da Wikipédia sobre UTF-8 .

Quando o grep encontra uma seqüência de bytes que não é um caractere válido na codificação esperada, ele não pode reconhecê-lo como um caractere, a linha não corresponde, é a saída. Como o seu terminal também não reconhece o caracter, você recebe um .

Existe uma solução no seu caso. Diga ao grep para não se incomodar com a codificação e considere um byte como um caractere.

env LANG=C grep ....

ou talvez

env LANG=C LC_ALL=C grep ....

Você pode testar facilmente:

Crie 2 arquivos, um codificado utf-8, um utf-16-be:

$ echo éléphant | tee file.std | iconv -f utf8 -t utf16be >file.utf16be

Verifique o conteúdo dos arquivos:

$ cat file*
éléphant
�l�phant

Tente o grep. A string utf16be não é reconhecida, não há saída:

$ grep '^.*$' file*
file.std:éléphant

Não use codificação. Um byte é um caractere. todas as cordas são combinadas o apenas significa que o terminal não reconhece a seqüência utf16be como um válido utf-8 char. Observe o uso de -a para dizer ao grep para considerar que o binário é é algum texto.

$ env LANG=C grep -a '^.*$' file*
file.std:éléphant
file.utf16be:�l�phant

Como alternativa, se você souber a codificação, use iconv para primeiro converter seu arquivo e, em seguida, use grep. Um dos seguintes itens deve funcionar.

iconv -f utf16   -t utf8 < file | grep ...
iconv -f utf16le -t utf8 < file | grep ...
iconv -f utf16be -t utf8 < file | grep ...
    
por exore 15.11.2016 / 19:04