Comment écrire des données au format CSV sous forme de chaîne (pas de fichier)?

119

Je souhaite diffuser des données comme [1,2,'a','He said "what do you mean?"']une chaîne au format CSV.

Normalement, on utiliserait csv.writer()pour cela, car il gère tous les cas extrêmes (virgule, échappement de guillemets, dialectes CSV, etc.) csv.writer().

Ma solution actuelle est cette fonction quelque peu piratée:

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

Quelqu'un peut-il donner une solution plus élégante qui gère toujours bien les cas de bord?

Edit: Voici comment j'ai fini par le faire:

def csv2string(data):
    si = StringIO.StringIO()
    cw = csv.writer(si)
    cw.writerow(data)
    return si.getvalue().strip('\r\n')
Li-aung Yip
la source
2
En Python 3, StringIO()est dans la iobibliothèque.
Aristide

Réponses:

67

Vous pouvez utiliser à la StringIOplace du vôtre Dummy_Writer:

Ce module implémente une classe de type fichier StringIO,, qui lit et écrit un tampon de chaîne (également appelé fichiers mémoire).

Il y a aussi cStringIO, qui est une version plus rapide de la StringIOclasse.

NPE
la source
165

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

Certains détails doivent être légèrement modifiés pour 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
la source
Bon exemple. :) En passant, quel est le comportement habituel lors de la rencontre de nouvelles lignes dans un fichier CSV? Est-il \nacceptable d'avoir au milieu des données, mais \r\nindique la fin d'un enregistrement, peu importe où il apparaît? (En supposant que vous soyez sur une plate-forme qui utilise \r\ncomme terminateur de ligne.)
Li-aung Yip
2
Devrait être output = StringIO.StringIO(), io.StringIO()lèvera TypeError: argument de chaîne attendu, obtenu 'str'.
Marboni
2
@Marboni: StringIO est parti dans Python 3 (qui est ce dans quoi ma solution est écrite), et je ne peux pas reproduire cette erreur dans Python 2.7.3 - bien que j'obtienne un TypeError dans la writer.writerow(...)ligne ( unicode argument expected, got 'str'). Je vais examiner cela.
Tim Pietzcker
1
@Marboni: Merci pour le heads-up: j'ai trouvé le problème avec l'aide de StackOverflow. Dans Python 2, vous avez besoin io.BytesIO()au lieu de io.StringIO().
Tim Pietzcker
1
@Marboni: En Python 2.7.9, il fonctionne avec StringIO.StringIO () ou io.BytesIO ().
srock
6

J'ai trouvé les réponses, dans l'ensemble, un peu déroutantes. Pour Python 2, cette utilisation a fonctionné pour moi:

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)
user2099484
la source
2

puisque j'utilise beaucoup cela pour diffuser les résultats de manière asynchrone de sanic à l'utilisateur en tant que données csv, j'ai écrit l'extrait suivant pour Python 3 .

L'extrait de code vous permet de réutiliser le même tampon StringIo encore et encore.


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"

exemple:

csv_formatter = ArgsToCsv()

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

Découvrez d'autres utilisations sur github gist: source et test

Johannes Valbjørn
la source
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
la source
3
Les réponses au code uniquement sont découragées, vous devriez ajouter des précisions à votre réponse
Raniz
-1

Voici la version qui fonctionne pour utf-8. csvline2string pour une seule ligne, sans saut de ligne à la fin, csv2string pour de nombreuses lignes, avec sauts de ligne:

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
la source