Wie schreibe ich Daten als Zeichenfolge (nicht als Datei) in das CSV-Format?


117

Ich möchte Daten wie [1,2,'a','He said "what do you mean?"']in eine CSV-formatierte Zeichenfolge umwandeln.

Normalerweise würde man csv.writer()dies verwenden, da es alle verrückten Randfälle behandelt (Komma-Escape, Anführungszeichen-Escape, CSV-Dialekte usw.). Der Haken ist, dass csv.writer()erwartet wird, dass die Ausgabe an ein Dateiobjekt und nicht an eine Zeichenfolge erfolgt.

Meine aktuelle Lösung ist diese etwas hackige Funktion:

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

Kann jemand eine elegantere Lösung geben, die die Randfälle immer noch gut handhabt?

Edit: So bin ich dazu gekommen:

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

2
In Python 3 StringIO()befindet sich in der ioBibliothek.
Aristide

Antworten:


66

Sie könnten StringIOanstelle Ihrer eigenen verwenden Dummy_Writer:

Dieses Modul implementiert eine dateiähnliche Klasse, StringIOdie einen Zeichenfolgenpuffer (auch als Speicherdateien bezeichnet) liest und schreibt.

Es gibt auch cStringIOeine schnellere Version der StringIOKlasse.


163

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'

Einige Details müssen für Python 2 etwas geändert werden:

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

Gutes Beispiel. :) Was ist als Nebenbemerkung das übliche Verhalten, wenn in einer CSV-Datei Zeilenumbrüche auftreten? Ist es in \nOrdnung, Daten in der Mitte zu haben, zeigt aber \r\ndas Ende eines Datensatzes an, unabhängig davon, wo er angezeigt wird? (Angenommen, Sie befinden sich auf einer Plattform, die \r\nals Leitungsterminator verwendet wird.)
Li-aung Yip

2
Sollte sein output = StringIO.StringIO(), io.StringIO()wird TypeError auslösen: String-Argument erwartet, 'str'.
Marboni

2
@Marboni: StringIO ist in Python 3 verschwunden (in dem meine Lösung geschrieben ist), und ich kann diesen Fehler in Python 2.7.3 nicht reproduzieren - obwohl ich einen TypeError in der writer.writerow(...)Zeile ( unicode argument expected, got 'str') bekomme . Werde das untersuchen.
Tim Pietzcker

1
@ Marboni: Danke für das Heads-up: Ich habe das Problem mit Hilfe von StackOverflow gefunden. In Python 2 benötigen Sie io.BytesIO()statt io.StringIO().
Tim Pietzcker

1
@Marboni: In Python 2.7.9 funktioniert es mit StringIO.StringIO () oder io.BytesIO ().
Srock

6

Alles in allem fand ich die Antworten etwas verwirrend. Für Python 2 funktionierte diese Verwendung für mich:

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

Da ich dies ziemlich oft benutze, um Ergebnisse asynchron von sanic zurück zum Benutzer als CSV-Daten zu streamen, habe ich das folgende Snippet für Python 3 geschrieben .

Mit dem Snippet können Sie denselben StringIo-Puffer immer wieder verwenden.


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"

Beispiel:

csv_formatter = ArgsToCsv()

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

Weitere Informationen finden Sie im Github-Gist: Quelle und 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
Von Nur-Code-Antworten wird abgeraten. Sie sollten Ihrer Antwort eine Klarstellung hinzufügen
Raniz,

-1

Hier ist die Version, die für utf-8 funktioniert. csvline2string für nur eine Zeile, ohne Zeilenumbrüche am Ende, csv2string für viele Zeilen, mit Zeilenumbrüchen:

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()
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.