2009-09-02 7 views
4

J'ai un fichier texte (.txt) qui pourrait être dans un format séparé par des tabulations ou un format séparé par des tuyaux, et j'ai besoin de le convertir en format CSV. J'utilise python 2.6. Quelqu'un peut-il me suggérer comment identifier le délimiteur dans un fichier texte, lire les données, puis le convertir en fichier séparé par des virgules.Comment convertir tab séparé, format de fichier CSV en Python en Python

Merci à l'avance

+1

http://docs.python.org/library/csv.html#examples – tonfa

+2

Pour obtenir une réponse raisonnable , vous devez spécifier comment l'auteur est en train de citer ou d'échapper le délimiteur (le cas échéant), et comment la citation ou le caractère échappé lui-même est cité ou échappé (le cas échéant). –

Répondre

0

Vous aimez cette

from __future__ import with_statement 
import csv 
import re 
with open(input, "r") as source: 
    with open(output, "wb") as destination: 
     writer= csv.writer(destination) 
     for line in input: 
      writer.writerow(re.split('[\t|]', line)) 
+2

1 pour pour la ligne en entrée (l'entrée est un chemin de fichier), -1 pour ne pas mentionner la citation \ échapper le délimiteur etc, et -1 pour avoir des espaces dans les endroits dopey dans votre code. –

+1

La citation/échappement est un non-problème. L'entrée (onglet ou pipe) ne peut pas être citée de manière significative. Peut-être échappé, mais c'est rare. Le quotient/échappement CSV est géré par 'csv'. –

+1

A propos des "lieux douteux" pour les espaces: après 30 ans de programmation dans des dizaines de langues, il y a des parties de PEP-8 que je ne vais pas suivre. –

0
for line in open("file"): 
    line=line.strip() 
    if "|" in line: 
     print ','.join(line.split("|")) 
    else: 
     print ','.join(line.split("\t")) 
+1

-1 pour split(). -1 pour la bande(); probablement la bande() est destinée à se débarrasser d'une nouvelle ligne; il fera cela PLUS il supprimera tous les autres espaces blancs (y compris les onglets); utilisez 'line.strip ('\ n')' à la place. -1 pour ne pas mentionner le quotient/échappement du délimiteur (et le quote/escape-char). –

6

je crains que vous ne pouvez pas identifier le delimiter sans savoir ce qu'il est. Le problème avec CSV est que, quoting ESR:

la version Microsoft du CSV est un exemple de manuel de comment ne pas concevoir un format de fichier texte.

Le délimiteur doit être échappé d'une manière ou d'une autre s'il peut apparaître dans des champs. Sans savoir, comment l'échappement est fait, l'identifier automatiquement est difficile. Echapper pourrait être fait de la manière UNIX, en utilisant une barre oblique inverse '\', ou la méthode Microsoft, en utilisant des guillemets qui doivent ensuite être échappés aussi. Ce n'est pas une tâche banale.

Donc, ma suggestion est d'obtenir une documentation complète de celui qui génère le fichier que vous voulez convertir. Ensuite, vous pouvez utiliser l'une des approches suggérées dans les autres réponses ou une variante.

Edit:

Python fournit csv.Sniffer qui peut vous aider à en déduire le format de votre DSV. Si votre entrée ressemble à ceci (notez le delimiter cité dans le premier champ de la deuxième rangée):

a|b|c 
"a|b"|c|d 
foo|"bar|baz"|qux 

Vous pouvez faire ceci:

import csv 

csvfile = open("csvfile.csv") 
dialect = csv.Sniffer().sniff(csvfile.read(1024)) 
csvfile.seek(0) 

reader = csv.DictReader(csvfile, dialect=dialect) 
for row in reader: 
    print row, 
# => {'a': 'a|b', 'c': 'd', 'b': 'c'} {'a': 'foo', 'c': 'qux', 'b': 'bar|baz'} 
# write records using other dialect 
+0

Je ne comprends pas le problème. La source est une tabulation ou un tube. La sortie CSV. Quelle "documentation complète" est requise? –

+2

Que se passe-t-il si un onglet ou un tube fait partie du contenu d'un champ? Vous devez savoir comment le délimiteur est échappé pour gérer cela. Il ne suffit pas de séparer les lignes sur le délimiteur. –

+0

Merci beaucoup pour la réponse –

0

Je suggère de prendre une partie du code d'exemple de les réponses existantes, ou peut-être mieux utiliser le module csv à partir de python et le changer pour d'abord supposer tab séparé, puis séparé de pipe, et produire deux fichiers de sortie qui sont séparés par des virgules. Ensuite, vous examinez visuellement les deux fichiers pour déterminer celui que vous voulez et choisissez cela.

Si vous avez réellement beaucoup de fichiers, alors vous devez essayer de trouver un moyen de détecter quel fichier est quel.
Un des exemples a ceci:

if "|" in line: 

Cela peut être suffisant: si la première ligne d'un fichier contient un tuyau, alors peut-être le fichier entier est séparé tuyau, sinon prendre un fichier séparé de tabulation.

Vous pouvez également corriger le fichier pour qu'il contienne un champ clé dans la première ligne facilement identifiable - ou peut-être que la première ligne contient des en-têtes de colonne pouvant être détectés.

1

Votre stratégie pourrait être la suivante:

  • Parse le fichier à la fois un lecteur de csv séparé par des tabulations et un lecteur de csv séparé pipe
  • calculer quelques statistiques sur les lignes résultant de décider qui ResultSet est le celui que vous voulez écrire. Une idée pourrait être de compter le nombre total de champs dans le jeu d'enregistrements deux (s'attendant à ce que l'onglet et le tuyau ne sont pas si communs). Un autre (si vos données sont fortement structurées et que vous vous attendez au même nombre de champs dans chaque ligne) pourrait mesurer l'écart-type du nombre de champs par ligne et prendre l'ensemble d'enregistrements avec le plus petit écart-type.

Dans l'exemple suivant, vous trouvez la statistique plus simple (nombre total de champs)

import csv 

piperows= [] 
tabrows = [] 

#parsing | delimiter 
f = open("file", "rb") 
readerpipe = csv.reader(f, delimiter = "|") 
for row in readerpipe: 
piperows.append(row) 
f.close() 

#parsing TAB delimiter 
f = open("file", "rb") 
readertab = csv.reader(f, delimiter = "\t") 
for row in readerpipe: 
tabrows.append(row) 
f.close() 

#in this example, we use the total number of fields as indicator (but it's not guaranteed to work! it depends by the nature of your data) 
#count total fields 
totfieldspipe = reduce (lambda x,y: x+ y, [len(f) for f in piperows]) 
totfieldstab = reduce (lambda x,y: x+ y, [len(f) for f in tabrows]) 

if totfieldspipe > totfieldstab: 
yourrows = piperows 
else: 
yourrows = tabrows 


#the var yourrows contains the rows, now just write them in any format you like 
Questions connexes