Convertendo CSV para TSV

18

Eu tenho vários arquivos CSV grandes e gostaria deles em TSV (formato separado por tabulação). A complicação é que existem vírgulas nos campos do arquivo CSV, por exemplo:

 A,,C,"D,E,F","G",I,"K,L,M",Z

Resultado esperado:

 A      C   D,E,F   G   I   K,L,M   Z

(onde os espaços em branco são guias 'hard')

Eu tenho Perl, Python e coreutils instalados neste servidor.

    
por DarkHeart 19.04.2017 / 04:24

12 respostas

34

Python

Adicione ao arquivo chamado csv2tab.sh e torne-o executável

#!/usr/bin/env python
import csv, sys
csv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))

Execuções de teste

$ echo 'A,,C,"D,E,F","G",I,"K,L,M",Z' | ./csv2tab.sh                         
A       C   D,E,F   G   I   K,L,M   Z

$ ./csv2tab.sh < data.csv > data.tsv && head data.tsv                                                   
1A      C   D,E,F   G   I   K,L,M   Z
2A      C   D,E,F   G   I   K,L,M   Z
3A      C   D,E,F   G   I   K,L,M   Z
    
por 19.04.2017 / 04:59
15

Por diversão, sed .

sed -E 's/("([^"]*)")?,/\t/g' file

Se o seu sed não for compatível com -E , tente com -r . Se o seu sed não suporta \t para uma tabulação literal, tente colocar uma tabulação literal (em muitas shells, ctrl - v tab ) ou no Bash, use uma string $'...' C-style (nesse caso, a barra invertida em precisa ser duplicada). Se você quiser manter as aspas, use em vez de (nesse caso, o par interno de parênteses é inútil e pode ser removido).

Isso não faz nenhuma tentativa de manipular aspas duplas entre aspas duplas; alguns dialetos CSV suportam isso duplicando as aspas duplas citadas (sic).

    
por 19.04.2017 / 09:07
12

Uma opção pode ser o módulo Text :: CSV do perl eg

perl -MText::CSV -lne 'BEGIN { $csv = Text::CSV->new() }
  print join "\t", $csv->fields() if $csv->parse($_)
' somefile

para demonstrar

echo 'A,,C,"D,E,F","G",I,"K,L,M",Z' |
  perl -MText::CSV -lne 'BEGIN { $csv = Text::CSV->new() }
  print join "\t", $csv->fields() if $csv->parse($_)
'
A       C   D,E,F   G   I   K,L,M   Z
    
por 19.04.2017 / 04:53
11

Usando o csvkit utility (Python), por exemplo:

$ csvformat -T in.csv > out.txt

Faz streaming, com citações e escape corretos de CSV e TSV

Está no apt e em outros gerenciadores de pacotes

    
por 19.04.2017 / 22:48
5

Perl

perl -lne '
   my $re = qr/,(?=(?:[^"]*"[^"]*")*(?![^"]*"))/;
   print join "\t", map { s/(?<!\)"//gr =~ s/\"/"/gr } split $re;
'

Awk

awk -v Q=\" -v FPAT="([^,]*)|(\"[^\"]+\")" -v OFS="\t" '{
   for (i=1; i<=NF; ++i)
      if ( substr($i, 1, 1) == Q )
         $i = substr($i, 2, length($i) - 2)
   print $1, $2, $3, $4, $5, $6, $7, $8
}'

Resultado:

A               C       D,E,F   G       I       K,L,M   Z
    
por 19.04.2017 / 05:29
4

A solução termonuclear de mata-moscas deve estar usando libreoffice. Enquanto link sugere que isso não é possível, mas está errado (ou apenas desatualizado?) e o seguinte comando funciona no meu 5.3.:

loffice "-env:UserInstallation=file:///tmp/LibO_Conversion" --convert-to csv:"Text - txt - csv (StarCalc)":9,34,UTF8 --headless --outdir some/path --infilter='csv:44,34,UTF8' *.csv

o argumento env pode ser ignorado, mas desta forma os documentos não aparecerão no seu documento recente.

    
por 20.04.2017 / 00:32
3

Se você tem ou pode instalar o utilitário csvtool :

csvtool -t COMMA -u TAB cat in.csv > out.ctv

Observe que, por algum motivo, csvtool não tem uma página de manual, mas csvtool --help imprimirá algumas centenas de linhas de documentação.

    
por 30.10.2017 / 23:11
3

Eu criei um conversor de CSV para TSV de código aberto que lida com as transformações descritas. É muito rápido, pode valer a pena dar uma olhada se houver uma necessidade contínua de converter arquivos CSV grandes. Tool faz parte do kit de ferramentas de utilitários TSV do eBay (documentação csv2tsv aqui ). As opções padrão são suficientes para a entrada descrita:

$ csv2tsv file.csv > file.tsv
    
por 17.07.2017 / 10:06
2

Vim

Apenas por diversão, as substituições de regex podem ser realizadas em Vim . Veja uma solução em potencial de quatro linhas, adaptada de: link

  1. As aspas entre aspas são primeiro alteradas para sublinhados (ou outro caracter ausente),
  2. Todas as outras vírgulas são substituídas por guias,
  3. Sublinhados dentro de citações são restaurados para vírgulas,
  4. Aspas são removidas.

    :%s/".\{-}"/\=substitute(submatch(0), ',', '_' , 'g')/g
    :%s/,/\t/g
    :%s/_/,/g
    :%s/"//g
    

Para criar um script da solução, as quatro linhas acima (sans leading colon) podem ser salvas em um arquivo, por exemplo, %código%. Abra cada CSV para edição com Vim e to_tsv.vim o script source na linha de comando Vim (adaptada de link ):

    :source /path/to/vim/filename/to_tsv.vim
    
por 20.04.2017 / 07:26
1

Usar mlr é quase sucinto, mas a desabilitação de cabeçalhos requer opções longas:

mlr --c2t --implicit-csv-header --headerless-csv-output cat file.csv 

Saída:

A       C   D,E,F   G   I   K,L,M   Z
    
por 13.04.2018 / 13:40
0

O texto a seguir é simplesmente uma correção para a resposta de @triplee de modo que ele retira quaisquer citações do campo final, assim como faz com todos os outros campos.

Para mostrar o que está sendo corrigido, abaixo está a resposta de triplee , além de uma pequena modificação nos dados de exemplo do OP com aspas adicionadas ao redor do campo final ' Z ' .

echo 'A,,C,"D,E,F","G",I,"K,L,M","Z"' |  sed -r -e 's/("([^"]*)")?,/\t/g'
A       C   D,E,F   G   I   K,L,M   "Z"

Você pode ver que " Z " é deixado com aspas em torno dele. Isso é diferente de como os campos internos são manipulados. Por exemplo, o ' G ' não tem aspas.

O comando a seguir usa uma segunda substituição para limpar a coluna final:

echo 'A,,C,"D,E,F","G",I,"K,L,M","Z"' |  sed -r -e 's/("([^"]*)")?,/\t/g' \
                                                -e 's/\t"([^"]*)"$/\t/'
A       C   D,E,F   G   I   K,L,M   Z
    
por 30.10.2017 / 22:41
0

Aqui está o exemplo da conversão de CSV em TSV usando jq utility :

$ jq -rn '@tsv "\(["A","","C","D,E,F","G","I","K,L,M","Z"])"'
A       C   D,E,F   G   I   K,L,M   Z

ou:

$ echo '["A","","C","D,E,F","G","I","K,L,M","Z"]' | jq -r @tsv
A       C   D,E,F   G   I   K,L,M   Z

No entanto, o formato CSV precisa estar bem formatado, portanto, cada string precisa ser citada.

Fonte: Formato de saída simples do TSV .

    
por 16.04.2018 / 22:27