Cria o csv a partir de um arquivo de texto inconsistente

4

Tenho registros vagamente estruturados em um arquivo que consiste em 3 ou 4 linhas de texto separadas (principalmente) por uma linha em branco. Nem todos os registros têm um separador de linha em branco, mas a última linha de cada um começa com a palavra "Adicionado". Eu gostaria de produzir um arquivo csv com cada registro em uma linha precedido por seu número de linha. Até agora só consegui produzir uma concatenação de todos os registros separados por um número arbitrário de espaços e uma vírgula redundante.

Logicamente, estou tentando alcançar o seguinte:

Read line, if line starts 'Added' keep newline at end
else replace 'newline' with ','
or if line is blank delete it
endif

Dados da amostra:

Peter Green  
Space Monkey at Area 51  
Joined  
Added by SF 3 weeks ago  
Will Rossiter  
Joined  
Added by SF 3 weeks ago

Dean Matthews  
Guitarist at Blues  
Joined  
Added by SF 3 weeks ago  
Hobbit Mak  
Farnborough, United Kingdom  
Joined  
Added by SF 3 weeks ago  

Keneth W Moorfield  
THE STOREMAN  
Joined  
Added by SF 3 weeks ago  
Mick Georgious  
Software Engineer  
Joined  
Added by SF 3 weeks ago
    
por SeniorMoments 05.08.2016 / 20:32

3 respostas

5

Tente:

awk '/./{ printf "%s%s", $0, (/Added/?"\n":",") }' data

Usando seus dados de entrada de amostra:

$ awk '/./{printf "%s%s",$0,(/Added/?"\n":",")}' data
Peter Green,Space Monkey at Area 51,Joined,Added by SF 3 weeks ago
Will Rossiter,Joined,Added by SF 3 weeks ago
Dean Matthews,Guitarist at Blues,Joined,Added by SF 3 weeks ago
Hobbit Mak,Farnborough, United Kingdom,Joined,Added by SF 3 weeks ago
Keneth W Moorfield,THE STOREMAN,Joined,Added by SF 3 weeks ago
Mick Georgious,Software Engineer,Joined,Added by SF 3 weeks ago

Como funciona:

  • /./{...}

    Isso executa os comandos em chaves apenas se a linha contiver um caractere. Em outras palavras, isso ignora linhas em branco.

  • printf "%s%s",$0,(/Added/?"\n":",")

    Isso imprime a linha, denotada $0 , seguida por uma vírgula ou uma nova linha, dependendo se a linha corresponde à regex Added .

por John1024 05.08.2016 / 20:39
3

Aqui está uma possível solução sed (com awk faz a numeração de linha):

$ sed -n -e :a -e '$!{/^$/!N}; /,Added/ {P;D}; s/\n/,/; ta' data | awk '{print NR","$0}'
1,Peter Green,Space Monkey at Area 51,Joined,Added by SF 3 weeks ago
2,Will Rossiter,Joined,Added by SF 3 weeks ago
3,Dean Matthews,Guitarist at Blues,Joined,Added by SF 3 weeks ago
4,Hobbit Mak,Farnborough, United Kingdom,Joined,Added by SF 3 weeks ago
5,Keneth W Moorfield,THE STOREMAN,Joined,Added by SF 3 weeks ago
6,Mick Georgious,Software Engineer,Joined,Added by SF 3 weeks ago 

Basicamente, continuamos anexando linhas de entrada não vazias e substituindo as novas linhas por vírgulas, exceto que verificamos a cada iteração para ver se temos um registro inteiro e, se o fizermos, cuspimos, por exemplo

  • definir um rótulo de programa :a
  • se não estiver no final do arquivo $! , em seguida, anexe linhas não vazias ao espaço de padrão {/^$/!N}
  • se estivermos no final de um registro /,Added/ , em seguida, imprima P e exclua D do espaço padrão
  • substitua a vírgula por nova linha s/,/\n/ , ramificando-se de volta para a no sucesso
por steeldriver 05.08.2016 / 21:08
2

FWIW, aqui está uma opção perl :

$ perl -lne '
    push @rec, $_ unless /^$/; if (/^Added/) {print join ",", ++$n, @rec; undef @rec;}
' data
1,Peter Green,Space Monkey at Area 51,Joined,Added by SF 3 weeks ago
2,Will Rossiter,Joined,Added by SF 3 weeks ago
3,Dean Matthews,Guitarist at Blues,Joined,Added by SF 3 weeks ago
4,Hobbit Mak,Farnborough, United Kingdom,Joined,Added by SF 3 weeks ago
5,Keneth W Moorfield,THE STOREMAN,Joined,Added by SF 3 weeks ago
6,Mick Georgious,Software Engineer,Joined,Added by SF 3 weeks ago 
    
por steeldriver 06.08.2016 / 01:09