CSV in Python, das unter Windows einen zusätzlichen Wagenrücklauf hinzufügt

231
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()

Es generiert eine Datei test.csvmit einem Extra \rin jeder Zeile, wie folgt:

test.csv

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

anstelle der erwarteten:

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

Warum passiert das oder ist das tatsächlich das gewünschte Verhalten?

Hinweis:

  • Dieses Verhalten kann bei Python 2 oder 3 auftreten.
Apalopohapa
quelle

Antworten:

311

Python 3:

with open('output.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    ...
with open('output.csv', 'w', newline='\n', encoding='utf-8') as f:
    writer = csv.writer(f)
    ...

Python 2:

Öffnen Sie Ihre Dateien unter Windows immer im Binärmodus ( "rb"oder "wb"), bevor Sie sie an csv.readeroder übergeben csv.writer.

Obwohl es sich bei der Datei um eine Textdatei handelt, wird CSV von den beteiligten Bibliotheken als Binärformat mit \r\ngetrennten Datensätzen angesehen. Wenn dieses Trennzeichen im Textmodus geschrieben ist, ersetzt die Python-Laufzeit das \nmit \r\n, daher das \r\r\nin der Datei beobachtete.

Siehe diese vorherige Antwort .

John Machin
quelle
3
Dies ist in Ordnung für ASCII, beendet jedoch die Codierung wie UTF-8. Jasons Lösung unten hat für mich funktioniert.
Tom
66
In Python 3 konnte ich das Problem mithilfe der folgenden Optionen für das Dateiobjekt beheben : open(..., "w", newline="\n", encoding="utf-8"). newlinekann auch eine leere Zeichenfolge sein, gleiches Ergebnis. "wb"funktioniert nicht in Python 3, Zeichenfolgen und die Pufferschnittstelle sind nicht kompatibel.
CodeManX
Elegante Art der Handhabung des zusätzlichen Wagenrücklaufs
ForeverLearner
2
Funktioniert nicht in Python2. Wenn Sie also mit 2 und 3 kompatibel sein müssen, verwenden Sie die Antwort von @ jason-r-coombs:writer = csv.writer(f, lineterminator='\n')
yossiz74
4
Dies ist eine echte Schande, dass eine so grundlegende, gemeinsame und einfache API nicht wie erforderlich funktioniert
SomethingSomething
248

Während @ John-Machin eine gute Antwort gibt, ist es nicht immer der beste Ansatz. Beispielsweise funktioniert es unter Python 3 nur, wenn Sie alle Ihre Eingaben in den CSV-Writer codieren. Außerdem wird das Problem nicht behoben, wenn das Skript sys.stdout als Stream verwenden möchte.

Ich schlage vor, stattdessen das Attribut 'lineterminator' beim Erstellen des Writers festzulegen:

import csv
import sys

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

Dieses Beispiel funktioniert mit Python 2 und Python 3 und erzeugt keine unerwünschten Zeilenumbrüche. Beachten Sie jedoch, dass es zu unerwünschten Zeilenumbrüchen kommen kann (das LF-Zeichen unter Unix-Betriebssystemen wird weggelassen).

In den meisten Fällen glaube ich jedoch, dass Verhalten vorzuziehen und natürlicher ist, als alle CSVs als Binärformat zu behandeln. Ich gebe diese Antwort als Alternative für Ihre Überlegung.

Jason R. Coombs
quelle
6
Dies ist meiner Meinung nach die beste Antwort. Wie wäre es, wenn Sie sys.platform aufrufen und dynamisch damit umgehen, wenn es unter Unix problematisch ist?
Sovemp
4
Die beste Antwort meiner Meinung nach auch, und lineterminator = '\ n' funktioniert wunderbar.
Eikonal
1
Können Sie ein Beispiel für das Problem geben, das auftritt, wenn Sie nicht "alle Ihre Eingaben in den CSV-Writer codieren"?
Stephen
ACHTUNG: Mit diesem Mittel \rwird nicht mehr entkommen! Sieht so aus, als wäre dies ein Fehler csvwriter, aber so wie es aussieht , bedeutet die Ausgabe von nicht konformer CSV, dass dies nicht der richtige Weg ist.
flow2k
Dies löste das ^MProblem für mich, während die 2 Vorschläge der akzeptierten Antwort nicht funktionierten.
user985366
55

In Python 3 (ich habe dies in Python 2 nicht versucht) können Sie dies auch einfach tun

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

gemäß Dokumentation .

Mehr dazu in der Fußnote des Dokuments :

Wenn newline = '' nicht angegeben wird, werden in Anführungszeichen eingebettete Zeilenumbrüche nicht korrekt interpretiert, und auf Plattformen, die beim Schreiben \ r \ n Linendings verwenden, wird ein zusätzliches \ r hinzugefügt. Es sollte immer sicher sein, newline = '' anzugeben, da das CSV-Modul seine eigene (universelle) Newline-Behandlung durchführt.

Yibo Yang
quelle
2
@ Yibo-Yang, Du hast mir viel Zeit gespart.
1man
4
GROSSARTIG. Ich bestätigte diesen Weg in Python 3.5
jef
Warum ist dies nicht das Standardverhalten?
Marc Stober
6

Sie können den Parameter lineterminator = '\ n' in den Befehl csv writer einfügen .

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
quelle
1
Mit Python 3.5.2 war dies das einzige, was für mich funktioniert hat (nun, ich habe es nur verwendet lineterminator='\n'). Das CSV-Modul schien der Ursprung von zu sein \r\n. Keine Reihe von Argumenten, opendie irgendeine Wirkung hatten.
Tommy
5

Ich bin mir nicht sicher, warum es genau passiert, aber wenn Sie Ihren Dateimodus von "w" auf "wb" ändern, wird das Problem behoben. Weitere Informationen finden Sie in meiner Antwort auf " Entfernen von ^ M ".

Ned Batchelder
quelle
3

Sie müssen das Attribut newline = "\ n" hinzufügen, um die Funktion wie folgt zu öffnen:

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

Beachten Sie, dass Sie bei Verwendung von DictWriter eine neue Zeile aus der Öffnungsfunktion und eine neue Zeile aus der Writerow-Funktion erhalten. Sie können newline = '' in der Öffnungsfunktion verwenden, um die zusätzliche Newline zu entfernen.

Erick Stone
quelle