Ho uno script Python 2.6 con caratteri speciali, codificato in Latin-1, che sto recuperando da un database SQL Server. Vorrei stampare questi caratteri, ma sono un po 'limitato perché sto usando una libreria che chiama lo stabilimento unicode
e non so come fare in modo che Python usi un codec diverso da ascii
.Latin-1 e la fabbrica unicode in Python
Lo script è uno strumento semplice per restituire i dati di ricerca da un database senza dover eseguire l'SQL direttamente in un editor SQL. Io uso la libreria PrettyTable 0.5 per visualizzare i risultati.
Il nucleo dello script è questo bit di codice. Le tuple che ottengo dal cursore contengono dati interi e string, e nessun dato Unicode. (Userei adodbapi
invece di pyodbc
, che mi otterrebbe Unicode, ma adodbapi
mi dà altri problemi.)
x = pyodbc.connect(cxnstring)
r = x.cursor()
r.execute(sql)
t = PrettyTable(columns)
for rec in r:
t.add_row(rec)
r.close()
x.close()
t.set_field_align("ID", 'r')
t.set_field_align("Name", 'l')
print t
ma la colonna Name
può contenere caratteri che non rientrano nel campo di ASCII. Io a volte un messaggio di errore come questo, in linea di 222 prettytable.pyc
, quando si arriva alla chiamata t.add_row
:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xed in position 12: ordinal not in range(128)
Questa è la riga 222 in prettytable.py
. Usa unicode
, che è la fonte dei miei problemi, e non solo in questo script, ma in altri script Python che ho scritto.
for i in range(0,len(row)):
if len(unicode(row[i])) > self.widths[i]: # This is line 222
self.widths[i] = len(unicode(row[i]))
Per favore dimmi cosa sto facendo male qui. Come posso fare in modo che unicode
funzioni senza l'hacking prettytable.py
o una delle altre librerie che uso? C'è anche un modo per farlo?
MODIFICA: l'errore non si verifica nell'istruzione print
, ma nella chiamata t.add_row
.
EDIT: Con l'aiuto di Bastien Léonard, ho trovato la seguente soluzione. Non è una panacea, ma funziona.
x = pyodbc.connect(cxnstring)
r = x.cursor()
r.execute(sql)
t = PrettyTable(columns)
for rec in r:
urec = [s.decode('latin-1') if isinstance(s, str) else s for s in rec]
t.add_row(urec)
r.close()
x.close()
t.set_field_align("ID", 'r')
t.set_field_align("Name", 'l')
print t.get_string().encode('latin-1')
Ho finito per dover decodificare all'ingresso e codificare sull'uscita. Tutto questo mi fa sperare che tutti portino le loro librerie su Python 3.x prima possibile!
Ho provato a inserire la codifica nella parte superiore dei miei script, ma ciò non funziona ancora. Proverò la decodifica esplicita, ma spero che ci sia una soluzione più generale. – eksortso
Probabilmente non si desidera impostare la codifica: latin1. Questo cambia la codifica della fonte dello script, non i suoi dati. –
@Glenn: L'ho suggerito perché pensavo che 'print t' possa stampare stringhe raw Latin1. –