CSV dengan Python menambahkan carriage return tambahan, di 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()

Ini menghasilkan file,, test.csvdengan tambahan \rdi setiap baris, seperti:

test.csv

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

bukannya yang diharapkan:

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

Mengapa ini terjadi, atau sebenarnya ini perilaku yang diinginkan?

catatan:

  • Perilaku ini dapat terjadi dengan Python 2 atau 3.
apalopohapa
sumber

Jawaban:

311

Python 3:

  • Seperti yang dijelaskan oleh YiboYang , setnewline=''
with open('output.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    ...
  • Seperti dicatat dalam komentar oleh CoDEmanX , aturnewline='\n'
with open('output.csv', 'w', newline='\n', encoding='utf-8') as f:
    writer = csv.writer(f)
    ...

Python 2:

Di Windows, selalu buka file Anda dalam mode biner ( "rb"atau "wb"), sebelum meneruskannya ke csv.readeratau csv.writer.

Meskipun file tersebut adalah file teks, CSV dianggap format biner oleh perpustakaan yang terlibat, dengan \r\nmemisahkan catatan. Jika pemisah itu ditulis dalam mode teks, runtime Python menggantikan \ndengan \r\n, maka \r\r\ndiamati dalam file.

Lihat jawaban ini sebelumnya .

John Machin
sumber
3
Ini bagus untuk ASCII tetapi akan mematikan encoding seperti UTF-8. Solusi Jason di bawah ini berhasil untuk saya.
Tom
66
Dalam Python 3, saya bisa memperbaikinya dengan menggunakan pilihan berikut untuk file objek: open(..., "w", newline="\n", encoding="utf-8"). newlinebisa juga berupa string kosong, hasil yang sama. "wb"tidak bekerja di Python 3, string dan antarmuka buffer tidak kompatibel.
CodeManX
Cara elegan menangani pengembalian gerbong ekstra
ForeverLearner
2
Tidak berfungsi di Python2, jadi jika Anda harus kompatibel dengan 2 dan 3, gunakan jawaban yang diberikan oleh @ jason-r-coombs:writer = csv.writer(f, lineterminator='\n')
yossiz74
4
Ini benar-benar memalukan bahwa API dasar, umum dan sederhana seperti itu tidak berfungsi seperti yang dipersyaratkan
SomethingSomething
248

Sementara @ john-machin memberikan jawaban yang baik, itu tidak selalu merupakan pendekatan terbaik. Misalnya, ini tidak berfungsi pada Python 3 kecuali jika Anda menyandikan semua input Anda ke penulis CSV. Juga, itu tidak mengatasi masalah jika skrip ingin menggunakan sys.stdout sebagai aliran.

Saya sarankan untuk mengatur atribut 'lineterminator' ketika membuat penulis:

import csv
import sys

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

Contoh itu akan bekerja pada Python 2 dan Python 3 dan tidak akan menghasilkan karakter baris baru yang tidak diinginkan. Perhatikan, bagaimanapun, bahwa itu dapat menghasilkan baris baru yang tidak diinginkan (menghilangkan karakter LF pada sistem operasi Unix).

Namun dalam kebanyakan kasus, saya percaya bahwa perilaku lebih disukai dan lebih alami daripada memperlakukan semua CSV sebagai format biner. Saya memberikan jawaban ini sebagai alternatif untuk pertimbangan Anda.

Jason R. Coombs
sumber
6
Ini jawaban terbaik menurut saya. Seperti itu menjadi masalah di Unix, bagaimana dengan memanggil sys.platform dan menghadapinya secara dinamis?
sovemp
4
Jawaban terbaik menurut saya juga, dan lineterminator = '\ n' berfungsi dengan baik.
eikonal
1
Bisakah Anda memberikan contoh masalah yang muncul jika Anda tidak "menyandikan semua masukan Anda ke penulis CSV"?
Stephen
WASPADALAH: menggunakan cara \rini tidak lagi lolos! Sepertinya ini adalah bug csvwriter, tetapi seperti berdiri, mengeluarkan CSV yang tidak sesuai berarti ini bukan cara yang harus dilakukan.
flow2k
Ini menyelesaikan ^Mmasalah bagi saya sementara 2 saran jawaban yang diterima tidak berfungsi.
user985366
55

Di Python 3 (saya belum mencoba ini di Python 2), Anda juga bisa melakukannya

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

sesuai dokumentasi .

Lebih lanjut tentang ini di catatan kaki doc :

Jika baris baru = '' tidak ditentukan, baris baru yang disematkan di dalam bidang yang dikutip tidak akan diartikan dengan benar, dan pada platform yang menggunakan \ r \ n linendings pada penulisan, tambahan \ r akan ditambahkan. Seharusnya selalu aman untuk menentukan newline = '', karena modul csv melakukan penanganan baris baru (universal) sendiri.

Yibo Yang
sumber
2
@ Yibo-Yang, Anda menghemat banyak waktu saya.
laki
4
BAGUS. Saya mengkonfirmasi cara ini dalam python 3.5
jef
Mengapa ini tidak menjadi perilaku default?
Marc Stober
6

Anda dapat memperkenalkan parameter lineterminator = '\ n' dalam perintah 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
sumber
1
Dengan Python 3.5.2, ini adalah satu-satunya hal yang bekerja untuk saya (well, saya hanya menggunakan lineterminator='\n'); modul CSV tampaknya merupakan asal dari \r\n. Tidak ada set argumen yang openberpengaruh.
Tommy
5

Saya tidak yakin persis mengapa itu terjadi, tetapi mengubah mode file Anda dari "w" ke "wb" memperbaikinya. Lihat jawaban saya untuk " cara menghapus ^ M " untuk lebih jelasnya.

Ned Batchelder
sumber
3

Anda harus menambahkan atribut newline = "\ n" untuk membuka fungsi seperti ini:

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

Perhatikan bahwa jika Anda menggunakan DictWriter, Anda akan memiliki baris baru dari fungsi terbuka dan baris baru dari fungsi writerow. Anda dapat menggunakan newline = '' di dalam fungsi terbuka untuk menghapus baris baru tambahan.

Erick Stone
sumber