¿Cómo escribo datos en formato CSV como una cadena (no un archivo)?

119

Quiero transmitir datos como [1,2,'a','He said "what do you mean?"']en una cadena con formato CSV.

Normalmente uno lo usaría csv.writer()para esto, porque maneja todos los casos extremos locos (escape de comas, escape de comillas, dialectos CSV, etc.) El problema es que csv.writer()espera generar una salida a un objeto de archivo, no a una cadena.

Mi solución actual es esta función algo hacky:

def CSV_String_Writeline(data):
    class Dummy_Writer:
        def write(self,instring):
            self.outstring = instring.strip("\r\n")
    dw = Dummy_Writer()
    csv_w = csv.writer( dw )
    csv_w.writerow(data)
    return dw.outstring

¿Alguien puede ofrecer una solución más elegante que aún maneje bien los casos extremos?

Editar: Así es como terminé haciéndolo:

def csv2string(data):
    si = StringIO.StringIO()
    cw = csv.writer(si)
    cw.writerow(data)
    return si.getvalue().strip('\r\n')
Li-aung Yip
fuente
2
En Python 3, StringIO()está en la iobiblioteca.
Aristide

Respuestas:

67

Podrías usar en StringIOlugar del tuyo Dummy_Writer:

Este módulo implementa una clase similar a un archivo StringIO, que lee y escribe un búfer de cadena (también conocido como archivos de memoria).

También existe cStringIO, que es una versión más rápida de la StringIOclase.

NPE
fuente
165

En Python 3:

>>> import io
>>> import csv
>>> output = io.StringIO()
>>> csvdata = [1,2,'a','He said "what do you mean?"',"Whoa!\nNewlines!"]
>>> writer = csv.writer(output, quoting=csv.QUOTE_NONNUMERIC)
>>> writer.writerow(csvdata)
59
>>> output.getvalue()
'1,2,"a","He said ""what do you mean?""","Whoa!\nNewlines!"\r\n'

Algunos detalles deben cambiarse un poco para Python 2:

>>> output = io.BytesIO()
>>> writer = csv.writer(output)
>>> writer.writerow(csvdata)
57L
>>> output.getvalue()
'1,2,a,"He said ""what do you mean?""","Whoa!\nNewlines!"\r\n'
Tim Pietzcker
fuente
Buen ejemplo. :) Como nota al margen, ¿cuál es el comportamiento habitual cuando se encuentran nuevas líneas dentro de un archivo CSV? ¿Está \nbien tenerlo en medio de los datos, pero \r\nindica el final de un registro sin importar dónde aparezca? (Suponiendo que está en una plataforma que utiliza \r\ncomo terminador de línea)
Li-aung Yip
2
Debería ser output = StringIO.StringIO(), io.StringIO()generará TypeError: argumento de cadena esperado, obtuvo 'str'.
Marboni
2
@Marboni: StringIO se ha ido en Python 3 (que es en lo que está escrita mi solución), y no puedo reproducir ese error en Python 2.7.3, aunque obtengo un TypeError en la writer.writerow(...)línea ( unicode argument expected, got 'str'). Investigaré esto.
Tim Pietzcker
1
@Marboni: Gracias por el aviso: encontré el problema con la ayuda de StackOverflow. En Python 2, necesita en io.BytesIO()lugar de io.StringIO().
Tim Pietzcker
1
@Marboni: En Python 2.7.9 funciona con StringIO.StringIO () o io.BytesIO ().
srock
6

Encontré las respuestas, en general, un poco confusas. Para Python 2, este uso funcionó para mí:

import csv, io

def csv2string(data):
    si = io.BytesIO()
    cw = csv.writer(si)
    cw.writerow(data)
    return si.getvalue().strip('\r\n')

data=[1,2,'a','He said "what do you mean?"']
print csv2string(data)
usuario2099484
fuente
2

ya que uso esto bastante para transmitir resultados de forma asincrónica desde sanic al usuario como datos csv, escribí el siguiente fragmento para Python 3 .

El fragmento le permite reutilizar el mismo búfer StringIo una y otra vez.


import csv
from io import StringIO


class ArgsToCsv:
    def __init__(self, seperator=","):
        self.seperator = seperator
        self.buffer = StringIO()
        self.writer = csv.writer(self.buffer)

    def stringify(self, *args):
        self.writer.writerow(args)
        value = self.buffer.getvalue().strip("\r\n")
        self.buffer.seek(0)
        self.buffer.truncate(0)
        return value + "\n"

ejemplo:

csv_formatter = ArgsToCsv()

output += csv_formatter.stringify(
    10,
    """
    lol i have some pretty
    "freaky"
    strings right here \' yo!
    """,
    [10, 20, 30],
)

Consulte el uso adicional en github gist: fuente y prueba

Johannes valbjørn
fuente
0
import csv
from StringIO import StringIO
with open('file.csv') as file:
    file = file.read()

stream = StringIO(file)

csv_file = csv.DictReader(stream)
Humberto Arocha
fuente
3
No se recomiendan las respuestas de solo código, debe agregar algunas aclaraciones a su respuesta
Raniz
-1

Aquí está la versión que funciona para utf-8. csvline2string para una sola línea, sin saltos de línea al final, csv2string para muchas líneas, con saltos de línea:

import csv, io

def csvline2string(one_line_of_data):
    si = BytesIO.StringIO()
    cw = csv.writer(si)
    cw.writerow(one_line_of_data)
    return si.getvalue().strip('\r\n')

def csv2string(data):
    si = BytesIO.StringIO()
    cw = csv.writer(si)
    for one_line_of_data in data:
        cw.writerow(one_line_of_data)
    return si.getvalue()
bjelli
fuente