Csv writer в Python с пользовательским цитированием
Я ищу способ определить пользовательский quoting
с csv.writer
в Python. Существует четыре встроенных способа для значений qoute:
csv.QUOTE_ALL, csv.QUOTE_MINIMAL, csv.QUOTE_NONNUMERIC, csv.QUOTE_NONE
Однако мне нужен механизм цитирования, который будет эмулировать Postgres 'FORCE QUOTE *
, то есть он будет указывать все значения, отличные от None. С помощью csv.QUOTE_ALL
Python превратит None в ''
, но вместо этого я хочу иметь пустую строку.
Возможно ли это сделать со встроенным модулем csv
(меня не интересуют хаки, я уже делаю это: P)? Или я вынужден написать/получить некоторый пользовательский парсер ssv?
И вообще: возможно ли написать собственный механизм кавычек для модуля csv
?
Ответы
Ответ 1
Отключить csv
цитирование и добавить сами кавычки:
def quote(col):
if col is None:
return ''
# uses double-quoting style to escape existing quotes
return '"{}"'.format(str(col).replace('"', '""'))
writer = csv.writer(fileobj, quoting=csv.QUOTE_NONE, escapechar='', quotechar='')
for row in rows:
writer.writerow(map(quote, row))
Установив как escapechar
, так и quotechar
на пустые строки, вы избегаете использования кода, цитирующего ваши уже цитируемые значения.
Вышеописанное работает до тех пор, пока вы не используете разделитель в значениях csv.
Обратите внимание, что к этому времени было бы проще сами писать строки с разделителями-запятыми:
with open(filename, 'w'), fd:
for row in rows:
fd.write(','.join(map(quote, row)) + '\r\n')
Ответ 2
Я написал собственный скрипт csv, который делает именно то, что я хочу:
class PostgresCSVWriter(object):
def __init__(self, stream, quotechar="\"", delimiter=",", escapechar="\\"):
self.stream = stream
self.quotechar = quotechar
self.delimiter = delimiter
self.escapechar = escapechar
self.buffer_size = 16384
def _convert_value(self, obj):
if obj is None:
return ""
value = str(obj)
value = value.replace(self.quotechar, self.quotechar+self.quotechar)
value = value.replace(self.delimiter, self.escapechar+self.delimiter)
return self.quotechar+value+self.quotechar
def _convert_row(self, row):
return self.delimiter.join(self._convert_value(v) for v in row) + "\r\n"
def writerow(self, row):
self.stream.write(self._convert_row(row))
def writerows(self, rows):
data = ""
counter = 0
for row in rows:
buf = self._convert_row(row)
data += buf
counter += len(buf)
if counter >= self.buffer_size:
self.stream.write(data)
data = ""
counter = 0
if data:
self.stream.write(data)
Если кто-нибудь видит какие-либо проблемы с этим, пожалуйста, дайте мне знать. Я все еще ищу решение с модулем csv
.