Как мне записать данные в формате CSV в виде строки (не файла)?

119

Я хочу преобразовать данные [1,2,'a','He said "what do you mean?"']в строку в формате CSV.

Обычно csv.writer()для этого можно использовать , потому что он обрабатывает все сумасшедшие граничные случаи (экранирование запятой, экранирование кавычек, диалекты CSV и т. Д.). Уловка заключается в том, что csv.writer()ожидается вывод в файловый объект, а не в строку.

Мое текущее решение - это несколько хакерская функция:

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

Может ли кто-нибудь предложить более элегантное решение, которое все еще хорошо справляется с крайними случаями?

Изменить: вот как я это сделал:

def csv2string(data):
    si = StringIO.StringIO()
    cw = csv.writer(si)
    cw.writerow(data)
    return si.getvalue().strip('\r\n')
Ли-Аунг Ип
источник
2
В Python 3 StringIO()находится в ioбиблиотеке.
Аристид

Ответы:

67

Вы можете использовать StringIOвместо своего Dummy_Writer:

Этот модуль реализует файловый класс, StringIOкоторый читает и записывает строковый буфер (также известный как файлы памяти).

Также cStringIOесть более быстрая версия StringIOкласса.

NPE
источник
165

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

Некоторые детали нужно немного изменить для 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'
Тим Пицкер
источник
Хороший пример. :) В качестве примечания, что обычно происходит при обнаружении новых строк внутри файла CSV? Можно ли \nразмещать в середине данных, но \r\nуказывает конец записи независимо от того, где она появляется? (Предполагая, что вы находитесь на платформе, которая используется \r\nв качестве терминатора линии.)
Ли-ан Ип,
2
Должно быть output = StringIO.StringIO(), io.StringIO()вызовет TypeError: ожидаемый строковый аргумент получил 'str'.
Марбони
2
@Marboni: StringIO отсутствует в Python 3 (это то, на чем написано мое решение), и я не могу воспроизвести эту ошибку в Python 2.7.3 - хотя я получаю TypeError в writer.writerow(...)строке ( unicode argument expected, got 'str'). Посмотрим на это.
Тим Пицкер,
1
@Marboni: Спасибо за предупреждение: я обнаружил проблему с помощью StackOverflow. В Python 2 io.BytesIO()вместо io.StringIO().
Тим Пицкер,
1
@Marboni: в Python 2.7.9 он работает с StringIO.StringIO () или io.BytesIO ().
srock
6

Я нашел ответы, в общем, немного запутанными. Для Python 2 это использование сработало для меня:

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
источник
2

так как я довольно часто использую это для асинхронной потоковой передачи результатов от sanic обратно к пользователю в виде данных csv, я написал следующий фрагмент для Python 3 .

Этот фрагмент позволяет повторно использовать один и тот же буфер 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"

пример:

csv_formatter = ArgsToCsv()

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

Ознакомьтесь с дальнейшим использованием на github gist: source и 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
Ответы,
состоящие
-1

Вот версия, которая работает для utf-8. csvline2string только для одной строки без разрывов строк в конце, csv2string для многих строк с разрывами строк:

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()
Бьелли
источник