Grava dados em movimento para Nova Linha

2

Eu tenho um arquivo CSV no qual poucos registros os dados estão sendo transferidos para Nova linha:

Exemplo:

  ABCD,1234,QWER
  ASDF
  ,2345,VGFT
  "ASDF,12",1212,ASDR 
  1234,ZXCV,ERTT

o resultado da saída deve ser:

  ABCD,1234,QWER
  ASDF,2345,VGFT
 "ASDF,12",1212,ASDR 
  1234,ZXCV,ERTT

Existe uma maneira de concatenar a 2ª e a 3ª colunas?

    
por Yarlly 20.07.2018 / 20:17

3 respostas

0

Com uma mistura de variáveis de shell, podemos fazer isso no GNU sed como mostrado:

nF='[^,]*';        # a normal unquoted csv field
qF='"[^"]*"';      # a quoted csv field
F="\($qF\|$nF\)";  # a csv field
ok="$F,$F,$F\$";   # a csv record with exactly 3 fields
# ok="\($F,\)\{2\}$F\$"; # an equivalent way to write out the regex for an ok csv record

sed -e "
    :a;/$ok/b       
    N;s/\n//;ba
" input.csv

saídas

ABCD,1234,QWER
ASDF,2345,VGFT
"ASDF,12",1212,ASDR 
1234,ZXCV,ERTT

funciona como

  • Construa a gramática de um csv usando uma mistura de variáveis de shell a serem usadas no sed.
  • Supondo que um registro csv não tenha mais de 3 campos.
  • Primeiro verifique se o registro csv está ok, ou seja, ele tem exatamente 3 campos. Nesse caso, basta imprimir o registro e ler o próximo registro.
  • OTW, ou seja, menos de 3 campos foram encontrados no registro csv atual, anexamos a próxima linha por meio do comando N , removemos o conector, um \n e, com esse espaço de padrão modificado, ramificar para o topo do código sed.
por 20.07.2018 / 21:11
1

Este é um hack ingênuo que funciona nos dados fornecidos:

$ awk -F, 'NF != 3 { printf("%s",$0); getline } 1' file.csv
ABCD,1234,QWER
ASDF,2345,VGFT
1234,ZXCV,ERTT

O que ele faz é usar awk para analisar o arquivo como um conjunto de dados delimitado por vírgulas. Se uma linha não tiver exatamente três campos ( NF != 3 ), o bit da linha que foi lida até agora será enviado como está sem nova linha à direita e a próxima linha será lida. O% final 1 é a abreviação de { print } e imprime todas as linhas.

Se o primeiro bloco foi acionado, esse% final 1 / print fará com que o restante da linha quebrada seja exibida no final do que foi gerado por printf .

Uma variação disso com sed :

$ sed -E '/^[^,]+,[^,]+,[^,]+$/!{ N; s/\n//; }' file.csv
ABCD,1234,QWER
ASDF,2345,VGFT
1234,ZXCV,ERTT

Novamente, isso pode não funcionar se as linhas forem quebradas de outras maneiras diferentes das mostradas nos dados de exemplo.

O que o script sed faz é testar cada linha com a expressão regular ^[^,]+,[^,]+,[^,]+$ . Se isso coincidir, temos uma linha que parece que deveria ser feita; três campos consistindo de caracteres diferentes de vírgulas, delimitados por vírgulas. Se não for o caso, a próxima linha é anexada ao final da linha atual com N , e a nova linha que sed insere entre as duas é removida.

O código sed segue a mesma lógica do código awk , pois acrescenta a próxima linha de dados se a linha atual estiver com defeito.

    
por 20.07.2018 / 20:33
1

Uma variação de um conhecido sed one-liner:

$ sed -e :a -e '$!N;s/\n[[:blank:]]*,/,/;ta' -e 'P;D' file.csv
  ABCD,1234,QWER
  ASDF,2345,VGFT
  "ASDF,12",1212,ASDR 
  1234,ZXCV,ERTT
    
por 20.07.2018 / 20:47