Bagaimana cara menulis data ke dalam format CSV sebagai string (bukan file)?

119

Saya ingin mentransmisikan data seperti [1,2,'a','He said "what do you mean?"']string berformat CSV.

Biasanya seseorang akan menggunakan csv.writer()untuk ini, karena menangani semua kasus tepi gila (pelolosan koma, pelolosan tanda kutip, dialek CSV, dll.) Tangkapannya adalah yang csv.writer()mengharapkan keluaran ke objek file, bukan ke string.

Solusi saya saat ini adalah fungsi yang agak hack ini:

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

Adakah yang bisa memberikan solusi yang lebih elegan yang masih menangani casing tepi dengan baik?

Sunting: Begini akhirnya saya melakukannya:

def csv2string(data):
    si = StringIO.StringIO()
    cw = csv.writer(si)
    cw.writerow(data)
    return si.getvalue().strip('\r\n')
Li-aung Yip
sumber
2
Di Python 3, StringIO()ada di ioperpustakaan.
Aristide

Jawaban:

67

Anda bisa menggunakan StringIOsebagai pengganti Anda sendiri Dummy_Writer:

Modul ini mengimplementasikan kelas seperti file StringIO,, yang membaca dan menulis buffer string (juga dikenal sebagai file memori).

Ada juga cStringIO, yang merupakan versi StringIOkelas yang lebih cepat .

NPE
sumber
165

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

Beberapa detail perlu sedikit diubah untuk 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
sumber
Contoh yang baik. :) Sebagai catatan samping, apa perilaku yang biasa terjadi saat menemukan baris baru di dalam file CSV? Apakah \nok untuk memiliki di tengah data, tetapi \r\nmenunjukkan akhir dari catatan di mana pun itu muncul? (Dengan asumsi Anda berada di platform yang digunakan \r\nsebagai terminator jalur.)
Li-aung Yip
2
Seharusnya output = StringIO.StringIO(), io.StringIO()akan memunculkan TypeError: argumen string diharapkan, mendapat 'str'.
Marboni
2
@Marboni: StringIO hilang dengan Python 3 (yang merupakan solusi saya dituliskan), dan saya tidak dapat mereproduksi kesalahan itu di Python 2.7.3 - meskipun saya mendapatkan TypeError di writer.writerow(...)baris ( unicode argument expected, got 'str'). Akan melihat ini.
Tim Pietzcker
1
@Marboni: Terima kasih atas perhatiannya: Saya menemukan masalah dengan bantuan StackOverflow. Dalam Python 2, Anda perlu io.BytesIO()bukan io.StringIO().
Tim Pietzcker
1
@Marboni: Dengan Python 2.7.9, ini bekerja dengan StringIO.StringIO () atau io.BytesIO ().
srock
6

Saya menemukan jawabannya, secara keseluruhan, agak membingungkan. Untuk Python 2, penggunaan ini berhasil untuk saya:

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)
pengguna2099484
sumber
2

karena saya menggunakan ini cukup banyak untuk mengalirkan hasil secara asynchronous dari sanic kembali ke pengguna sebagai data csv saya menulis potongan berikut untuk Python 3 .

Cuplikan memungkinkan Anda menggunakan kembali buffer StringIo yang sama berulang kali.


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"

contoh:

csv_formatter = ArgsToCsv()

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

Lihat penggunaan lebih lanjut di github gist: source and test

Johannes valbjørn
sumber
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
sumber
3
Jawaban hanya kode tidak disarankan, Anda harus menambahkan beberapa klarifikasi pada jawaban Anda
Raniz
-1

Ini versi yang berfungsi untuk utf-8. csvline2string hanya untuk satu baris, tanpa linebreak di akhir, csv2string untuk banyak baris, dengan linebreak:

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
sumber