CSV en Python agregando un retorno de carro adicional, en 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()

Genera un archivo, test.csvcon un extra \ren cada fila, así:

test.csv

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

en lugar de lo esperado:

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

¿Por qué sucede esto o es realmente el comportamiento deseado?

Nota:

  • Este comportamiento puede ocurrir con Python 2 o 3.
apalopohapa
fuente

Respuestas:

311

Python 3:

  • Según lo descrito por YiboYang , establezcanewline=''
with open('output.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    ...
  • Como se señaló en los comentarios de CoDEmanX , establezcanewline='\n'
with open('output.csv', 'w', newline='\n', encoding='utf-8') as f:
    writer = csv.writer(f)
    ...

Python 2:

En Windows, abra siempre sus archivos en modo binario ( "rb"o "wb"), antes de pasarlos a csv.readero csv.writer.

Aunque el archivo es un archivo de texto, CSV es considerado un formato binario por las bibliotecas involucradas, con \r\nregistros separados. Si ese separador está escrito en modo texto, el tiempo de ejecución de Python reemplaza el \ncon \r\n, de ahí el \r\r\nobservado en el archivo.

Ver esta respuesta anterior .

John Machin
fuente
3
Esto está bien para ASCII pero matará la codificación como UTF-8. La solución de Jason a continuación funcionó para mí.
Tom
66
En Python 3, yo era capaz de arreglarlo mediante el uso de las siguientes opciones para el objeto de archivo: open(..., "w", newline="\n", encoding="utf-8"). newlineTambién puede ser una cadena en blanco, el mismo resultado. "wb"no funciona en Python 3, las cadenas y la interfaz del búfer son incompatibles.
CodeManX
Forma
2
No funciona en Python2, así que si necesita ser compatible con 2 y 3, use la respuesta dada por @ jason-r-coombs:writer = csv.writer(f, lineterminator='\n')
yossiz74
44
Es una verdadera lástima que una API tan básica, común y simple no funcione como se requiere
SomethingSomething
248

Si bien @ john-machin da una buena respuesta, no siempre es el mejor enfoque. Por ejemplo, no funciona en Python 3 a menos que codifique todas sus entradas al escritor CSV. Además, no soluciona el problema si el script quiere usar sys.stdout como la secuencia.

En su lugar, sugiero configurar el atributo 'lineterminator' al crear el escritor:

import csv
import sys

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

Ese ejemplo funcionará en Python 2 y Python 3 y no producirá los caracteres de nueva línea no deseados. Sin embargo, tenga en cuenta que puede producir nuevas líneas indeseables (omitiendo el carácter LF en los sistemas operativos Unix).

Sin embargo, en la mayoría de los casos, creo que el comportamiento es preferible y más natural que tratar todos los CSV como un formato binario. Proporciono esta respuesta como una alternativa para su consideración.

Jason R. Coombs
fuente
66
Esta es la mejor respuesta en mi opinión. En cuanto a que sea problemático en Unix, ¿qué hay de llamar a sys.platform y tratarlo dinámicamente?
Sovemp
44
La mejor respuesta en mi opinión también, y lineterminator = '\ n' funciona de maravilla.
eikonal
1
¿Puede dar un ejemplo del problema que surge si no "codifica todas sus entradas al escritor CSV"?
Stephen
CUIDADO: ¡usar este medio \rya no se escapa! Parece que esto es un error csvwriter, pero tal como está, generar CSV no conforme significa que este no es el camino a seguir.
flow2k
Esto resolvió el ^Mproblema para mí, mientras que las 2 sugerencias de la respuesta aceptada no funcionaron.
user985366
55

En Python 3 (no he probado esto en Python 2), también puedes simplemente hacer

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

según la documentación .

Más sobre esto en la nota al pie del documento :

Si no se especifica newline = '', las nuevas líneas incrustadas dentro de los campos entre comillas no se interpretarán correctamente, y en las plataformas que usan \ r \ n linendings al escribir se agregará un \ r adicional. Siempre debería ser seguro especificar newline = '', ya que el módulo csv realiza su propio manejo de línea nueva (universal).

Yibo Yang
fuente
2
@ Yibo-Yang, me ahorraste mucho tiempo.
hombre
44
EXCELENTE.
Confirmé de
¿Por qué no sería este el comportamiento predeterminado?
Marc Stober
6

Puede introducir el parámetro lineterminator = '\ n' en el comando 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
fuente
1
Con Python 3.5.2, esto fue lo único que funcionó para mí (bueno, solo lo usé lineterminator='\n'); El módulo CSV parecía ser el origen de \r\n. Ningún conjunto de argumentos opentuvo ningún efecto.
Tommy
5

No estoy seguro de por qué está sucediendo exactamente, pero cambiar el modo de archivo de "w" a "wb" lo arregla. Vea mi respuesta a " cómo eliminar ^ M " para obtener más detalles.

Ned Batchelder
fuente
3

Debe agregar el atributo newline = "\ n" para abrir una función como esta:

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

Tenga en cuenta que si usa DictWriter, tendrá una nueva línea desde la función de abrir y una nueva línea desde la función de escritura. Puede usar newline = '' dentro de la función abierta para eliminar la nueva línea adicional.

Erick Stone
fuente