2013-10-11 5 views
10

Sto cercando un modo per definire quoting personalizzato con csv.writer in Python. Ci sono 4 modi incorporati per qoute valori:csv writer in Python con quoting personalizzato

csv.QUOTE_ALL, csv.QUOTE_MINIMAL, csv.QUOTE_NONNUMERIC, csv.QUOTE_NONE 

Tuttavia ho bisogno di un meccanismo di quoting che emulerà Postgres' FORCE QUOTE *, vale a dire lo citerà tutti i valori non Nessuno. Con csv.QUOTE_ALL Python trasformerà None in '' ma vorrei invece avere una stringa vuota.

È possibile farlo con il modulo integrato csv (non sono interessato agli hack, lo sto già facendo: P)? O sono obbligato a scrivere/ottenere un parser csv personalizzato?

E in generale: è possibile scrivere un meccanismo di quotazione personalizzato per il modulo csv?

risposta

9

Disabilita csv citando e aggiungere le citazioni da soli:

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)) 

Impostando sia escapechar e quotechar di svuotare le stringhe si evita il modulo indicando i valori già citati.

Quanto sopra funziona fintanto che non si utilizza il delimitatore nei valori csv.

Si noti che da questo momento sarebbe solo più facile scrivere le linee delimitati da virgole te:

with open(filename, 'w'), fd: 
    for row in rows: 
     fd.write(','.join(map(quote, row)) + '\r\n') 
+1

Già provato: il problema è che devi specificare 'escapechar' con' QUOTE_NONE' e quindi evita le virgolette. – freakish

+0

@freakish: solo se 'quotechar' è ancora impostato. –

+0

È '' 'di default, non è vero? – freakish

4

ho scritto il mio scrittore csv che fa esattamente quello che voglio:

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) 

Se qualcuno vede qualche problema con esso, quindi per favore fatemelo sapere. Sto ancora cercando una soluzione con il modulo csv.