Puis-je importer un fichier CSV et déduire automatiquement le délimiteur?
Je veux importer deux types de fichiers CSV, certains utilisent"; " pour délimiteur et d'autres utilisent ",". Jusqu'à présent, j'ai basculé entre les deux lignes suivantes:
reader=csv.reader(f,delimiter=';')
Ou
reader=csv.reader(f,delimiter=',')
Est-il possible de ne pas spécifier le délimiteur et de laisser le programme vérifier le bon délimiteur?
Les solutions ci-dessous (Blender et sharth) semblent bien fonctionner pour les fichiers séparés par des virgules (générés avec Libroffice) mais pas pour les fichiers séparés par des points-virgules (générés avec MS Office). Voici les premières lignes d'un fichier séparé par des points-virgules:
ReleveAnnee;ReleveMois;NoOrdre;TitreRMC;AdopCSRegleVote;AdopCSAbs;AdoptCSContre;NoCELEX;ProposAnnee;ProposChrono;ProposOrigine;NoUniqueAnnee;NoUniqueType;NoUniqueChrono;PropoSplittee;Suite2LecturePE;Council PATH;Notes
1999;1;1;1999/83/EC: Council Decision of 18 January 1999 authorising the Kingdom of Denmark to apply or to continue to apply reductions in, or exemptions from, excise duties on certain mineral oils used for specific purposes, in accordance with the procedure provided for in Article 8(4) of Directive 92/81/EEC;U;;;31999D0083;1998;577;COM;NULL;CS;NULL;;;;Propos* are missing on Celex document
1999;1;2;1999/81/EC: Council Decision of 18 January 1999 authorising the Kingdom of Spain to apply a measure derogating from Articles 2 and 28a(1) of the Sixth Directive (77/388/EEC) on the harmonisation of the laws of the Member States relating to turnover taxes;U;;;31999D0081;1998;184;COM;NULL;CS;NULL;;;;Propos* are missing on Celex document
5 réponses
Le csv
module semble vous recommandons d'utiliser le csv sniffer pour ce problème.
, Ils donnent l'exemple suivant, que j'ai adapté à votre cas.
with open('example.csv', 'rb') as csvfile: # python 3: 'r',newline=""
dialect = csv.Sniffer().sniff(csvfile.read(1024), delimiters=";,")
csvfile.seek(0)
reader = csv.reader(csvfile, dialect)
# ... process CSV file contents here ...
Essayons.
[9:13am][wlynch@watermelon /tmp] cat example
#!/usr/bin/env python
import csv
def parse(filename):
with open(filename, 'rb') as csvfile:
dialect = csv.Sniffer().sniff(csvfile.read(), delimiters=';,')
csvfile.seek(0)
reader = csv.reader(csvfile, dialect)
for line in reader:
print line
def main():
print 'Comma Version:'
parse('comma_separated.csv')
print
print 'Semicolon Version:'
parse('semicolon_separated.csv')
print
print 'An example from the question (kingdom.csv)'
parse('kingdom.csv')
if __name__ == '__main__':
main()
Et nos entrées d'échantillon
[9:13am][wlynch@watermelon /tmp] cat comma_separated.csv
test,box,foo
round,the,bend
[9:13am][wlynch@watermelon /tmp] cat semicolon_separated.csv
round;the;bend
who;are;you
[9:22am][wlynch@watermelon /tmp] cat kingdom.csv
ReleveAnnee;ReleveMois;NoOrdre;TitreRMC;AdopCSRegleVote;AdopCSAbs;AdoptCSContre;NoCELEX;ProposAnnee;ProposChrono;ProposOrigine;NoUniqueAnnee;NoUniqueType;NoUniqueChrono;PropoSplittee;Suite2LecturePE;Council PATH;Notes
1999;1;1;1999/83/EC: Council Decision of 18 January 1999 authorising the Kingdom of Denmark to apply or to continue to apply reductions in, or exemptions from, excise duties on certain mineral oils used for specific purposes, in accordance with the procedure provided for in Article 8(4) of Directive 92/81/EEC;U;;;31999D0083;1998;577;COM;NULL;CS;NULL;;;;Propos* are missing on Celex document
1999;1;2;1999/81/EC: Council Decision of 18 January 1999 authorising the Kingdom of Spain to apply a measure derogating from Articles 2 and 28a(1) of the Sixth Directive (77/388/EEC) on the harmonisation of the laws of the Member States relating to turnover taxes;U;;;31999D0081;1998;184;COM;NULL;CS;NULL;;;;Propos* are missing on Celex document
Et si nous exécutons le programme exemple:
[9:14am][wlynch@watermelon /tmp] ./example
Comma Version:
['test', 'box', 'foo']
['round', 'the', 'bend']
Semicolon Version:
['round', 'the', 'bend']
['who', 'are', 'you']
An example from the question (kingdom.csv)
['ReleveAnnee', 'ReleveMois', 'NoOrdre', 'TitreRMC', 'AdopCSRegleVote', 'AdopCSAbs', 'AdoptCSContre', 'NoCELEX', 'ProposAnnee', 'ProposChrono', 'ProposOrigine', 'NoUniqueAnnee', 'NoUniqueType', 'NoUniqueChrono', 'PropoSplittee', 'Suite2LecturePE', 'Council PATH', 'Notes']
['1999', '1', '1', '1999/83/EC: Council Decision of 18 January 1999 authorising the Kingdom of Denmark to apply or to continue to apply reductions in, or exemptions from, excise duties on certain mineral oils used for specific purposes, in accordance with the procedure provided for in Article 8(4) of Directive 92/81/EEC', 'U', '', '', '31999D0083', '1998', '577', 'COM', 'NULL', 'CS', 'NULL', '', '', '', 'Propos* are missing on Celex document']
['1999', '1', '2', '1999/81/EC: Council Decision of 18 January 1999 authorising the Kingdom of Spain to apply a measure derogating from Articles 2 and 28a(1) of the Sixth Directive (77/388/EEC) on the harmonisation of the laws of the Member States relating to turnover taxes', 'U', '', '', '31999D0081', '1998', '184', 'COM', 'NULL', 'CS', 'NULL', '', '', '', 'Propos* are missing on Celex document']
Il est également probablement intéressant de noter quelle version de python j'utilise.
[9:20am][wlynch@watermelon /tmp] python -V
Python 2.7.2
Étant donné un projet qui traite à la fois des fichiers CSV délimités (virgule) et | (barre verticale), qui sont bien formés, j'ai essayé ce qui suit (comme indiqué à https://docs.python.org/2/library/csv.html#csv.Sniffer):
dialect = csv.Sniffer().sniff(csvfile.read(1024), delimiters=',|')
Cependant, sur un fichier / - delimited, l'exception "Could not determine delimiter" a été renvoyée. Il semblait raisonnable de spéculer que l'heuristique sniff pourrait fonctionner mieux si chaque ligne a le même nombre de délimiteurs (sans compter ce qui pourrait être inclus dans citation). Donc, au lieu de lire les 1024 premiers octets du fichier, j'ai essayé de lire les deux premières lignes dans leur intégralité:
temp_lines = csvfile.readline() + '\n' + csvfile.readline()
dialect = csv.Sniffer().sniff(temp_lines, delimiters=',|')
Jusqu'à présent, cela fonctionne bien pour moi.
Pour résoudre le problème, j'ai créé une fonction qui lit la première ligne d'un fichier (en-tête) et détecte le délimiteur.
def detectDelimiter(csvFile):
with open(csvFile, 'r') as myCsvfile:
header=myCsvfile.readline()
if header.find(";")!=-1:
return ";"
if header.find(",")!=-1:
return ","
#default delimiter (MS Office export)
return ";"
Et si vous utilisez DictReader
vous pouvez le faire:
#!/usr/bin/env python
import csv
def parse(filename):
with open(filename, 'rb') as csvfile:
dialect = csv.Sniffer().sniff(csvfile.read(), delimiters=';,')
csvfile.seek(0)
reader = csv.DictReader(csvfile, dialect=dialect)
for line in reader:
print(line['ReleveAnnee'])
J'ai utilisé ceci avec Python 3.5
et cela a fonctionné de cette façon.
Je ne pense pas qu'il puisse y avoir une solution parfaitement générale à cela (l'une des raisons pour lesquelles je pourrais utiliser ,
comme délimiteur est que certains de mes champs de données doivent pouvoir inclure ;
...). Une heuristique simple pour décider pourrait être de simplement lire la première ligne( ou plus), compter combien de caractères ,
et ;
Il contient (en ignorant éventuellement les guillemets à l'intérieur, si quoi que ce soit crée vos .csv
fichiers cite les entrées correctement et uniformément), et devinez que le plus fréquent des deux est le droit délimiteur.