O que é uma boa maneira de filtrar um arquivo de texto para remover linhas vazias?

11

Eu tenho um arquivo .csv (em um mac) que tem várias linhas vazias, por exemplo:

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum 

lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum 

lorem ipsum ","2","3","4"

Que eu quero converter para:

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum  lorem ipsum ","2","3","4"

Eu sei que deve haver um forro, mas não sei o awk nem o sed. Alguma dica muito apreciada!

    
por pitosalas 28.11.2012 / 18:07

12 respostas

3

Sei que isso seria mais fácil se eu desse o arquivo, mas infelizmente ele continha informações confidenciais que eu não podia compartilhar. Enquanto isso, escrevi-me um script de rubi que parecia fazer o truque:

require 'csv'
c = CSV.open("outfile1.csv", "w")
CSV.foreach("data.csv", :encoding => 'windows-1251:utf-8') do |row|
  row = row.map { |a| a.class == String ? a.gsub(/\r/, '') : a}
  c << row
end
c.close

Obrigado a todos por ajudarem!

    
por 28.11.2012 / 21:05
11

Você pode usar o modo -v (jogo de inversão) do grep para fazer isso:

grep -v '^$' old-file.csv > new-file.csv

Observe que esses arquivos precisam ser diferentes, devido ao modo como os redirecionamentos de shell funcionam. O arquivo de saída é aberto (e esvaziado) antes que o arquivo de entrada seja lido. Se você tiver moreutils (não por padrão no Mac OS X), você pode usar sponge para contornar isso:

grep -v '^$' file.csv | sponge file.csv

Mas, claro, você terá mais dificuldade em voltar se algo der errado.

Se você "linhas em branco", na verdade, pode conter espaços (parece que eles fazem), então você pode usar isso em vez disso:

egrep -v '^[[:space:]]*$' old-file.csv > new-file.csv

Isso irá ignorar linhas em branco, assim como linhas contendo apenas espaços em branco. Você pode, claro, fazer a mesma transformação sponge nela.

    
por 28.11.2012 / 18:10
8

A opção mais fácil é apenas grep . . Aqui, o ponto significa "corresponde a qualquer coisa", portanto, se a linha estiver vazia, ela não será correspondida. Outros, imprime toda a linha como é.

    
por 28.11.2012 / 23:34
6

Para remover linhas vazias, no lugar , com ksh93:

sed '/./!d' file 1<>; file

O operador de redirecionamento <>; é específico para ksh93 e é o mesmo que o operador padrão <> , exceto que ksh trunca o arquivo após o comando ser finalizado.

sed '/./!d' é uma maneira complicada de escrever grep . , mas infelizmente o GNU grep reclama se seu stdout apontar para o mesmo arquivo que seu stdin. Você diria que alguém poderia escrever:

grep . file | cat 1<>; file

Mas, infelizmente, há um bug no ksh93 (pelo menos na minha versão (93u +)), em que o arquivo parece estar truncado para comprimento zero nesse caso.

grep . file | { cat; } 1<>; file

Parece resolver esse bug, mas agora é muito mais complexo do que o comando sed.

    
por 28.11.2012 / 19:08
5

Aqui está um Perl one-liner para ele:

perl -pi -e 's/^\s*\n//' yourfile

EDIT: Melhor código baseado nos comentários da ruakh abaixo.

    
por 28.11.2012 / 18:10
5

Com base no esclarecimento nos comentários da sua pergunta, algo como:

awk -v RS= -v ORS= 1

pode fazer o que quiser.

Um separador de registro vazio é um caso especial que diz a awk que os registros devem ser parágrafos (separados por sequências de linhas vazias). Configurar o separador de registros de saída para a cadeia vazia também significa que o conteúdo desses parágrafos (sem os separadores) deve ser concatenado. 1 é apenas uma condição true para imprimir todos os registros.

Isso, no entanto, omitiria a nova linha, então você poderia fazer:

awk -v RS= -v ORS= '1;END{if (NR) printf "\n"}'
    
por 28.11.2012 / 20:54
2
awk '
    length == 0 {next} 
    /^[^"]/ && /"$/ {print; next} 
    {printf("%s", $0)}
' filename

produz

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
    
por 28.11.2012 / 20:47
2

Encontrei uma ideia para uma possível solução em stackoverflow .

sed -i ':a;N;$!ba;s/[^"]\n\s*\n/ /g' file.csv

Você provavelmente deveria fazer backup do seu arquivo csv antes de testá-lo, mas pelo menos pelo exemplo que você forneceu, ele funciona perfeitamente.

Uma boa explicação sobre o funcionamento interno dessa expressão é oferecida na resposta, apenas a editei para procurar linhas que não terminem com " ( [^"]\n ).

    
por 28.11.2012 / 19:52
1

Se, a partir de sua própria resposta, você quiser remover caracteres de nova linha contidos dentro de strings entre aspas, você poderia fazer:

 perl -0777 -pe 's/".*?"/$_=$&;s:\n::g;$_/gse'

Você também pode usar o flag -i do perl para editar os arquivos no lugar .

 perl -0777 -pe 's/".*?"/$_=$&;s:\n::g;$_/gse' file1 file2...

Ou com o GNU awk:

 awk -v RS=\" 'NR%2==0 {gsub("\n","")}; {printf "%s", $0 RT}'

ou:

 awk -vRS=\" '1-NR%2{gsub("\n","")}{ORS=RT}1'

(se você está competindo pelo menor)

Observe que eles assumem que não há caracteres de aspas duplas com escape na entrada.

    
por 29.11.2012 / 08:24
0

Parece que você quer mais do que remover linhas vazias, mas remover todas as sequências de 2 ou mais caracteres de nova linha.

O que você poderia fazer com o perl:

perl -0777 -pe 's/\n{2,}//gs' file

Você também pode usar o flag -i do perl para editar os arquivos no lugar .

perl -0777 -pi -e 's/\n{2,}//gs' file1 file2...
    
por 29.11.2012 / 08:20
0

Existe uma maneira cada vez mais curta de remover linhas vazias em AWK :

awk 'NF' file

Mas, para obter a saída desejada, tudo o que você precisa é de um simples liner:

awk 'NF {printf("%s ", $0); i++;} !(i % 2) {printf("\n");}' file

Explicação

Em AWK , uma linha vazia significa que a linha / registro não possui campos, ou seja, a variável NF (Number of Fields) é zero. O único forro acima só será executado quando NF > 0 , imprimindo todas as linhas, mas as vazias.

O i++ é o contador de linhas não vazias.

O !(i % 2) é usado para imprimir duas linhas consecutivas não vazias no caminho da saída desejada, ou seja, sempre que um múltiplo de 2 for encontrado, a modulo declaração !(i % 2) produzirá 1, o que termina a concatenação de duas linhas não vazias.

    
por 05.03.2016 / 02:16
0

Você pode usar o Vim no modo Ex:

ex -sc v/./d -cx b.csv
  1. v/./ encontra linhas vazias

  2. d delete

  3. x salvar e fechar

por 11.04.2016 / 03:08