Jak zapisać dane w formacie CSV jako ciąg (nie plik)?


119

Chcę rzutować dane jak [1,2,'a','He said "what do you mean?"']ciąg w formacie CSV.

Zwykle by to używał csv.writer(), ponieważ obsługuje wszystkie szalone przypadki skrajne (ucieczki przecinkami, znaki cudzysłowu, dialekty CSV itp.) csv.writer().

Moje obecne rozwiązanie to nieco zmyślona funkcja:

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

Czy ktoś może dać bardziej eleganckie rozwiązanie, które nadal dobrze radzi sobie z krawędziami?

Edycja: Oto jak to zrobiłem:

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

2
W Pythonie 3 StringIO()znajduje się w iobibliotece.
Aristide

Odpowiedzi:


67

Możesz użyć StringIOzamiast własnego Dummy_Writer:

Ten moduł implementuje klasę podobną do pliku StringIO, która odczytuje i zapisuje bufor ciągów (znany również jako pliki pamięci).

Jest też cStringIOszybsza wersja tej StringIOklasy.


165

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

Niektóre szczegóły wymagają nieco zmiany w Pythonie 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'

Dobry przykład. :) Na marginesie, jakie jest typowe zachowanie podczas napotykania znaków nowej linii w pliku CSV? Czy \nmożna mieć w środku danych, ale \r\nwskazuje koniec rekordu bez względu na to, gdzie się pojawia? (Zakładając, że jesteś na platformie \r\n
używanej

2
Powinno być output = StringIO.StringIO(), io.StringIO()spowoduje zgłoszenie błędu TypeError: oczekiwano argumentu string, otrzymano „str”.
Marboni

2
@Marboni: StringIO zniknęło w Pythonie 3 (w którym jest napisane moje rozwiązanie) i nie mogę odtworzyć tego błędu w Pythonie 2.7.3 - chociaż otrzymuję TypeError w writer.writerow(...)linii ( unicode argument expected, got 'str'). Przyjrzę się temu.
Tim Pietzcker

1
@Marboni: Dzięki za ostrzeżenie: znalazłem problem z pomocą StackOverflow. W Pythonie 2 io.BytesIO()zamiast io.StringIO().
Tim Pietzcker

1
@Marboni: W Pythonie 2.7.9 działa z StringIO.StringIO () lub io.BytesIO ().
srock

6

W sumie odpowiedzi wydały mi się nieco zagmatwane. W przypadku Pythona 2 to użycie zadziałało:

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

ponieważ używam tego dość często do asynchronicznego przesyłania wyników z Sanic z powrotem do użytkownika w postaci danych csv, napisałem następujący fragment kodu dla Pythona 3 .

Fragment umożliwia wielokrotne używanie tego samego bufora StringIo.


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"

przykład:

csv_formatter = ArgsToCsv()

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

Sprawdź dalsze użycie na stronie github: źródło i 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
Odpowiedzi zawierające tylko kod są odradzane, należy dodać wyjaśnienie do swojej odpowiedzi
Raniz

-1

Oto wersja, która działa dla utf-8. csvline2string dla jednej linii, bez podziałów linii na końcu, csv2string dla wielu linii, z podziałami linii:

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()
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.