Processamento de arquivo CSV - remova aspas e substitua o delimitador de vírgula pela guia

2

Precisa converter arquivos delimitados por um comando shell. Existem duas variações para o arquivo de entrada recebido, uma com aspas duplas e outra sem aspas e ambos os arquivos têm a vírgula como um delimitador. O requisito é substituir a vírgula por TAB e remover as aspas se o arquivo tiver aspas duplas senão substituir a vírgula. Um arquivo é enviado com aspas se seus campos também tiverem uma vírgula que precisa ser ignorada durante a transformação. O comando único deve ser efetivo no Awk 3.x no ambiente RHEL 6.x.

por exemplo. Arquivo 1 com aspas duplas:

"Jhon","Carpenter","CA,TX,NJ"
"Mike","Painter","WA,GA,MI"

Pós-transformação, deve ser separado por TAB:

Jhon   Carpenter   CA,TX,NJ 
Mike   Painter     WA,GA,MI 

por exemplo. Arquivo 2 sem aspas duplas:

EMP1,123456,CA 
EMP2,456789,TX 

Pós-transformação, deve ser separado por TAB:

EMP1 123456   CA 
EMP2   456789   TX
    
por Arijit Choudhury 31.08.2017 / 23:56

5 respostas

1

Este script sed curto pode processar os dois tipos de arquivos (ou até mesmo os mistos com linhas de primeiro e segundo tipo):

sed '/"/!s/,/\t/g;s/","/\t/g; s/"//g'

Como ele não agrupa expressões sem loop, ele deve ser muito mais rápido que seu script.

Você parece ter o GNU sed , então \t funciona, caso contrário, use o literal TAB.

    
por 01.09.2017 / 09:16
3

Usando csvkit :

$ csvformat -T file1.csv
Jhon    Carpenter       CA,TX,NJ
Mike    Painter WA,GA,MI

$ csvformat -T file2.csv
EMP1    123456  CA
EMP2    456789  TX

A saída para file1.csv parece um pouco errada, mas isso ocorre porque as guias não estão alinhadas corretamente. Existe um separador entre todas as colunas.

O CSVKit é uma caixa de ferramentas baseada em Python de vários utilitários de shell relacionados a CSV. Ele faz uma análise CSV adequada e pode ser usado para consultar, formatar e converter arquivos CSV.

Se o primeiro arquivo, por exemplo, tiver cabeçalhos adequados, transformar isso em JSON seria tão fácil quanto

$ csvjson file1.csv
[{"First": "Jhon", "Last": "Carpenter", "Stuff": "CA,TX,NJ"}, {"First": "Mike", "Last": "Painter", "Stuff": "WA,GA,MI"}]
    
por 01.09.2017 / 08:42
1

Várias abordagens:

Para o file1 (com aspas duplas):

- awk abordagem:

awk -F'"' '{ r=""; for(i=1;i<NF;i++) 
     if ($i~/^[[:alnum:]]/) r=(r!="")? r OFS $i : $i; print r }' OFS='\t' file1

- sed abordagem:

sed 's/","/\t/g; s/"//g;' file1

A saída (para ambas as abordagens):

Jhon    Carpenter   CA,TX,NJ
Mike    Painter WA,GA,MI

----------

Para o file2 (sem aspas duplas) - basta aplicar o comando tr :

tr ',' '\t' <file2

A saída:

EMP1    123456  CA
EMP2    456789  TX

----------

Abordagem unificada para a condição " mesmo comando deve bastar o tipo de arquivo ":

awk -v quoted=$(grep -cm1 '"' file1) 'BEGIN{ FS=(quoted)? "\"" : ","; }
     { r=""; for(i=1;i<=NF;i++) if(!quoted || $i~/^[[:alnum:]]/) r=(r!="")? r OFS $i : $i; 
             print r }' OFS='\t' file1
    
por 01.09.2017 / 00:29
0

Bem, esta solução não é tão elegante quanto a resposta de Kusalananda e eu acho que não seria tão rápido quanto você quer, mas deve funcionar bem.

#!/usr/bin/env bash

for file; do

  while read -r line; do

    if <<< "${line}" grep -F -e '"' > '/dev/null' 2>&1; then
      <<< "${line}" \
      grep -P -o -e '(?<=")([^,].*?)(?=")' |
      tr $'\n' $'\t' | rev | cut -c 2- | rev
    else
      <<< "${line}" \
      tr ',' $'\t'
    fi

  done < "${file}"

done

Exemplo:

$ cat file1
"Jhon","Carpenter","CA,TX,NJ"
"Mike","Painter","WA,GA,MI"

$ cat file2
EMP1,123456,CA
EMP2,456789,TX

$ script.sh file1 file2
Jhon    Carpenter   CA,TX,NJ
Mike    Painter WA,GA,MI
EMP1    123456  CA
EMP2    456789  TX
    
por 01.09.2017 / 09:13
0

Os dados de CSV exigem um analisador de CSV adequado. Eu gosto da resposta de Kusalananda. Você também pode usar uma linguagem como o Ruby que vem com um módulo csv:

ruby -rcsv -e '
  out = CSV.new($stdout, {:col_sep => "\t"})
  CSV.foreach(ARGV.shift) {|row| out << row} 
' file1.csv
    
por 01.09.2017 / 12:21