web-dev-qa-db-fra.com

Conversion de CSV en TSV

J'ai un certain nombre de fichiers CSV volumineux et je les souhaite en TSV (format séparé par des tabulations). La complication est qu'il y a des virgules dans les champs du fichier CSV, par exemple:

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

Production attendue:

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

(où les espaces entre les deux sont des onglets "durs")

J'ai Perl, Python et coreutils installés sur ce serveur.

28
DarkHeart

Python

Ajouter au fichier nommé csv2tab.sh, et le rendre exécutable

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

Essais

$ 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
41
cricket_007

Utilisation de csvkit (Python), par exemple:

$ csvformat -T in.csv > out.txt

Est-ce que le streaming, avec des citations et échappements CSV et TSV corrects

C'est dans apt et autres gestionnaires de paquets

19
Neil McGuigan

Pour le plaisir, sed.

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

Si votre sed ne prend pas en charge -E, essayez avec -r. Si votre sed ne prend pas en charge \t pour un onglet littéral, essayez de mettre un onglet littéral (dans de nombreux shells, ctrl-vtab) ou dans Bash, utilisez un $'...' Chaîne de style C (auquel cas la barre oblique inverse dans \2 doit être doublé). Si vous souhaitez conserver les guillemets, utilisez \1 au lieu de \2 (auquel cas la paire de parenthèses internes est inutile et peut être supprimée).

Cela n'essaie pas de gérer les guillemets doubles échappés à l'intérieur des guillemets doubles; certains dialectes CSV le supportent en doublant le double guillemet cité (sic).

19
tripleee

Une option pourrait être le module Perl's Text :: CSV par exemple.

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

démontrer

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
13
steeldriver

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
}'

Résultat:

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

Si vous avez, ou pouvez installer, l'utilitaire csvtool:

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

Notez que pour une raison quelconque, csvtool n'a pas de page de manuel, mais csvtool --help imprimera quelques centaines de lignes de documentation.

5
Keith Thompson

La solution thermonucléaire de tapette à mouches doit utiliser libreoffice. Alors que https://ask.libreoffice.org/en/question/19042/is-is-possible-to-convert-comma-separated-value-csv-to-tab-separated-value-tsv-via -headless-mode / suggère que ce n'est pas possible mais que c'est faux (ou juste obsolète?) et la commande suivante fonctionne sur mon 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

l'argument env peut être ignoré mais de cette façon, les documents n'apparaîtront pas dans votre document récent.

5
chx

Utiliser mlr est presque succinct, mais la désactivation des en-têtes nécessite de longues options:

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

Production:

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

J'ai créé un convertisseur CSV vers TSV open source qui gère les transformations décrites. C'est assez rapide, peut valoir le coup d'œil s'il y a un besoin continu de convertir de gros fichiers CSV. L'outil fait partie de boîte à outils d'utilitaires TSV d'eBay (documentation csv2tsv ici ). Les options par défaut suffisent pour l'entrée décrite:

$ csv2tsv file.csv > file.tsv

Une considération lors de la conversion de CSV en TSV est la gestion des délimiteurs de champ et d'enregistrement (virgule et nouvelle ligne) dans les données. CSV utilise une syntaxe d'échappement. Si l'objectif est d'utiliser la sortie avec des outils Unix comme cut, awk, etc., la sortie doit être exempte d'échappements. La plupart des solutions répertoriées ici produisent des échappements de style CSV lorsque des délimiteurs se trouvent dans les données. csv2tsv se différencie des autres solutions en ce qu'il produit TSV sans échappements. Consultez la documentation pour plus de détails.

Pour voir ce que fait une solution particulière, convertissez un CSV contenant des virgules, des tabulations, des guillemets et des retours à la ligne dans les données. Par exemple:

$ echo $'Line,Field1,Field2\n1,"Comma: |,|","Quote: |""|"\n"2","TAB: |\t|","Newline: |\n|"' | <conversion-script-or-command>

Les solutions générant des échappements mettront des guillemets doubles dans les champs contenant des guillemets, des nouvelles lignes ou des tabulations.

4
JonDeg

Vim

Juste pour le plaisir, les substitutions d'expression régulière peuvent être effectuées dans Vim . Voici une solution potentielle à quatre lignes, adaptée de: https://stackoverflow.com/questions/33332871/remove-all-commas-between-quotes-with-a-vim-regex

  1. Les virgules entre guillemets sont d'abord remplacées par des traits de soulignement (ou tout autre caractère absent),
  2. Toutes les autres virgules sont remplacées par des tabulations,
  3. Les soulignements à l'intérieur des guillemets sont restaurés en virgules,
  4. Les guillemets sont supprimés.

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

Pour écrire un peu la solution, les quatre lignes ci-dessus (sans signe deux-points) peuvent être enregistrées dans un fichier, par ex. to_tsv.vim. Ouvrez chaque CSV pour le modifier avec Vim et source the to_tsv.vim script sur la ligne de commande Vim (adapté de https://stackoverflow.com/questions/3374179/run-vim-script -from-vim-commandline/8806874 # 8806874 ):

    :source /path/to/vim/filename/to_tsv.vim
2
jubilatious1

Avec Perl, en supposant que les champs csv n'ont pas de " Ni de nouvelles lignes ou d'onglets intégrés:

Perl -pe 's{"(.*?)"|,}{$1//"\t"}ge'
1
Stéphane Chazelas

Voici l'exemple de conversion de CSV en TSV à l'aide de l'utilitaire jq :

$ 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

Cependant, le format CSV doit être bien formaté, donc chaque chaîne doit être citée.

Source: format de sortie TSV simple .

1
kenorb

Ce qui suit est simplement une correction de la réponse de @ tripleee afin qu'il supprime toutes les citations du champ final comme il fait à tous les autres domaines.

Pour montrer ce qui est corrigé, voici la réponse d'un tripleee , plus une légère modification des données d'exemple de l'OP avec des guillemets ajoutés autour de la finale ' [~ # ~] z [~ # ~] 'champ.

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

Vous pouvez voir que ' [~ # ~] z [~ # ~] ' est laissé avec des guillemets autour. Ceci est différent de la façon dont les champs internes sont traités. Par exemple, le ' [~ # ~] g [~ # ~] ' n'a pas de guillemets dessus.

La commande suivante utilise une deuxième substitution pour nettoyer la dernière colonne:

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