Come scrivo i dati in formato CSV come stringa (non file)?


119

Voglio trasmettere dati come [1,2,'a','He said "what do you mean?"']una stringa in formato CSV.

Normalmente si userebbe csv.writer()per questo, perché gestisce tutti i casi limite pazzi (escape di virgole, escape di virgolette, dialetti CSV, ecc.) Il problema è che si csv.writer()aspetta l'output su un oggetto file, non su una stringa.

La mia soluzione attuale è questa funzione un po 'hacker:

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

Qualcuno può dare una soluzione più elegante che gestisca ancora bene i casi limite?

Modifica: ecco come ho finito per farlo:

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

2
In Python 3, StringIO()è nella iolibreria.
Aristide

Risposte:


67

Potresti usare al StringIOposto del tuo Dummy_Writer:

Questo modulo implementa una classe simile a file StringIO, che legge e scrive un buffer di stringa (noto anche come file di memoria).

C'è anche cStringIO, che è una versione più veloce della StringIOclasse.


165

In 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'

Alcuni dettagli devono essere modificati un po 'per 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'

Buon esempio. :) Come nota a margine, qual è il comportamento usuale quando si incontrano nuove righe all'interno di un file CSV? Va \nbene avere nel mezzo dei dati, ma \r\nindica la fine di un record indipendentemente da dove appare? (Supponendo che tu sia su una piattaforma che utilizza \r\ncome terminatore di linea.)
Li-aung Yip

2
Dovrebbe essere output = StringIO.StringIO(), io.StringIO()solleverà TypeError: argomento stringa previsto, ottenuto 'str'.
Marboni

2
@Marboni: StringIO è scomparso in Python 3 (che è ciò in cui è scritta la mia soluzione) e non posso riprodurre quell'errore in Python 2.7.3, anche se ottengo un TypeError nella writer.writerow(...)riga ( unicode argument expected, got 'str'). Esamineremo questo.
Tim Pietzcker

1
@Marboni: Grazie per l'avvertenza: ho trovato il problema con l'aiuto di StackOverflow. In Python 2, è necessario io.BytesIO()invece di io.StringIO().
Tim Pietzcker

1
@Marboni: In Python 2.7.9 funziona con StringIO.StringIO () o io.BytesIO ().
srock

6

Ho trovato le risposte, tutto sommato, un po 'confuse. Per Python 2, questo utilizzo ha funzionato per me:

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)

2

poiché lo uso abbastanza per trasmettere i risultati in modo asincrono da sanic all'utente come dati csv, ho scritto il seguente frammento per Python 3 .

Lo snippet ti consente di riutilizzare lo stesso buffer StringIo più e più volte.


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"

esempio:

csv_formatter = ArgsToCsv()

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

Controlla l'ulteriore utilizzo in GitHub Gist: sorgente e test


0
import csv
from StringIO import StringIO
with open('file.csv') as file:
    file = file.read()

stream = StringIO(file)

csv_file = csv.DictReader(stream)

3
Le risposte di solo codice sono scoraggiate, dovresti aggiungere qualche chiarimento alla tua risposta
Raniz

-1

Ecco la versione che funziona per utf-8. csvline2string per una sola riga, senza interruzioni di riga alla fine, csv2string per molte righe, con interruzioni di riga:

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()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.