CSV en Python ajoutant un retour chariot supplémentaire, sous Windows

232
import csv
outfile = file('test.csv', 'w')
writer = csv.writer(outfile, delimiter=',', quoting=csv.QUOTE_MINIMAL)
writer.writerow(['hi','dude'])
writer.writerow(['hi2','dude2'])
outfile.close()

Il génère un fichier, test.csvavec un extra \rà chaque ligne, comme ceci:

test.csv

hi,dude\r\r\nhi2,dude2\r\r\n

au lieu de l'attendu:

hi,dude\r\nhi2,dude2\r\n

Pourquoi cela se produit-il ou est-ce réellement le comportement souhaité?

Remarque:

  • Ce problème peut se produire avec Python 2 ou 3.
apalopohapa
la source

Réponses:

312

Python 3:

  • Comme décrit par YiboYang , définisseznewline=''
with open('output.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    ...
  • Comme indiqué dans les commentaires de CoDEmanX , définisseznewline='\n'
with open('output.csv', 'w', newline='\n', encoding='utf-8') as f:
    writer = csv.writer(f)
    ...

Python 2:

Sous Windows, ouvrez toujours vos fichiers en mode binaire ( "rb"ou "wb"), avant de les passer à csv.readerou csv.writer.

Bien que le fichier soit un fichier texte, CSV est considéré comme un format binaire par les bibliothèques concernées, avec \r\ndes enregistrements séparés. Si ce séparateur est écrit en mode texte, le runtime Python remplace le \npar \r\n, d'où l' \r\r\nobservé dans le fichier.

Voir cette réponse précédente .

John Machin
la source
3
C'est bien pour ASCII mais tuera le codage comme UTF-8. La solution de Jason ci-dessous a fonctionné pour moi.
Tom
66
En Python 3, j'ai pu le réparer en utilisant les options suivantes pour l'objet de fichier: open(..., "w", newline="\n", encoding="utf-8"). newlinepeut également être une chaîne vide, même résultat. "wb"ne fonctionne pas dans Python 3, les chaînes et l'interface de tampon sont incompatibles.
CodeManX
Manière élégante de gérer le retour de chariot supplémentaire
ForeverLearner
2
Ne fonctionne pas en Python2, donc si vous devez être compatible avec 2 et 3, utilisez la réponse donnée par @ jason-r-coombs:writer = csv.writer(f, lineterminator='\n')
yossiz74
4
C'est vraiment dommage qu'une telle API basique, commune et simple ne fonctionne pas comme requis
SomethingSomething
248

Bien que @ john-machin donne une bonne réponse, ce n'est pas toujours la meilleure approche. Par exemple, cela ne fonctionne pas sur Python 3 à moins que vous n'encodiez toutes vos entrées dans le rédacteur CSV. En outre, il ne résout pas le problème si le script souhaite utiliser sys.stdout comme flux.

Je suggère plutôt de définir l'attribut 'lineterminator' lors de la création de l'écrivain:

import csv
import sys

doc = csv.writer(sys.stdout, lineterminator='\n')
doc.writerow('abc')
doc.writerow(range(3))

Cet exemple fonctionnera sur Python 2 et Python 3 et ne produira pas les caractères de nouvelle ligne indésirables. Notez, cependant, qu'il peut produire des sauts de ligne indésirables (en omettant le caractère LF sur les systèmes d'exploitation Unix).

Dans la plupart des cas, cependant, je pense que le comportement est préférable et plus naturel que de traiter tous les CSV comme un format binaire. Je fournis cette réponse comme une alternative pour votre considération.

Jason R. Coombs
la source
6
C'est la meilleure réponse à mon avis. Pour ce qui est problématique sous Unix, que diriez-vous d'appeler sys.platform et de le traiter dynamiquement?
sovemp
4
La meilleure réponse à mon avis aussi, et lineterminator = '\ n' fonctionne à merveille.
eikonal
1
Pouvez-vous donner un exemple du problème qui se pose si vous "n'encodez pas toutes vos entrées dans le rédacteur CSV"?
Stephen
ATTENTION: l'utilisation de ce moyen \rne s'échappe plus! Il semble que ce soit un bug csvwriter, mais en l'état, la sortie de CSV non conforme signifie que ce n'est pas la voie à suivre.
flow2k
Cela a résolu le ^Mproblème pour moi alors que les 2 suggestions de la réponse acceptée n'ont pas fonctionné.
user985366
55

En Python 3 (je n'ai pas essayé cela en Python 2), vous pouvez aussi simplement faire

with open('output.csv','w',newline='') as f:
    writer=csv.writer(f)
    writer.writerow(mystuff)
    ...

selon la documentation .

Plus à ce sujet dans la note de bas de page du doc :

Si newline = '' n'est pas spécifié, les sauts de ligne incorporés dans les champs entre guillemets ne seront pas interprétés correctement, et sur les plates-formes qui utilisent les lignes \ r \ n en écriture, un \ r supplémentaire sera ajouté. Il devrait toujours être prudent de spécifier newline = '', puisque le module csv fait sa propre gestion (universelle) de newline.

Yibo Yang
la source
2
@ Yibo-Yang, tu m'as fait gagner beaucoup de temps.
1man
4
GÉNIAL. J'ai confirmé de cette façon en python 3.5
jef
Pourquoi ne serait-ce pas le comportement par défaut?
Marc Stober
6

Vous pouvez introduire le paramètre lineterminator = '\ n' dans la commande csv writer.

import csv
delimiter='\t'
with open('tmp.csv', '+w', encoding='utf-8') as stream:
    writer = csv.writer(stream, delimiter=delimiter, quoting=csv.QUOTE_NONE, quotechar='',  lineterminator='\n')
    writer.writerow(['A1' , 'B1', 'C1'])
    writer.writerow(['A2' , 'B2', 'C2'])
    writer.writerow(['A3' , 'B3', 'C3'])
Wesam Na
la source
1
Avec Python 3.5.2, c'était la seule chose qui fonctionnait pour moi (enfin, j'ai utilisé juste lineterminator='\n'); le module CSV semblait être à l'origine de \r\n. Aucun ensemble d'arguments openn'a eu d'effet.
Tommy
5

Je ne sais pas exactement pourquoi cela se produit, mais changer votre mode de fichier de "w" à "wb" le corrige. Voir ma réponse à " comment supprimer ^ M " pour plus de détails.

Ned Batchelder
la source
3

Vous devez ajouter l'attribut newline = "\ n" pour ouvrir une fonction comme celle-ci:

with open('file.csv','w',newline="\n") as out:
    csv_out = csv.writer(out, delimiter =';')
Gregor Ažbe
la source
2

Notez que si vous utilisez DictWriter, vous aurez une nouvelle ligne de la fonction open et une nouvelle ligne de la fonction writerow. Vous pouvez utiliser newline = '' dans la fonction ouverte pour supprimer la nouvelle ligne supplémentaire.

Erick Stone
la source