This is an old revision of the document!
Table of Contents
Unicode con Python
Vedere l'articolo Python Unicode Tutorial.
Oppure queste slide: Unicode In Python, Completely Demystified.
Input: lettura da database
Si assume che nel database i campi testo siano codificati UTF-8. Sarebbe opportuno che il charset del database sia dichiarato UTF-8 in fase di creazione dello stesso; con PostgreSQL si tratta dell'impostazione predefinita, con MySQL invece no. Con MySQL è comunque possibile memorizzare testo UTF-8 anche se il charset dichiarato è quello predefinito latin1
, per fortuna perché MySQL ha ancora molti problemi nella gestione di UTF-8 (spazio occupato dalle stringhe, limiti nella dimensione degli indici, ecc.).
Per assicurarsi che Python decodifichi correttamente le stringhe lette da un database:
import MySQLdb conn = MySQLdb.connect(host='localhost', user='dbuser', passwd='dbpass', db='dbname', charset='utf8') curs = conn.cursor() # Not strictly needed: #curs.execute("SET CHARACTER SET utf8") curs.execute("SELECT * FROM table") rows = curs.fetchall() for row in rows: field0 = row[0] print type(field0), field0 ...
La funzione type()
restituisce unicode
, questo vuol dire che Python ha saputo decodificare correttamente l'input (grazie alla dichiarazione del parametro charset
nella connect()
) e memorizza internamente la stringa nel formato ottimale unicode. Questo consente a Python di operare correttamente sulle stringhe, ad esempio quando si applica la funzione len()
i caratteri multibyte vengono valutati correttamente di lunghezza pari a uno.
Se si omette la dichiarazione del charset
nella connect()
, la stringa letta dal database avrebbe un generico type() = str
. Per decodificare correttamente il contenuto bisognerebbe modificare il programma come segue:
curs.execute("SET CHARACTER SET utf8") curs.execute("SELECT * FROM table") rows = curs.fetchall() for row in rows: field0 = row[0].decode('utf-8') print type(field0), field0 ...
Input/Output: lettura/scrittura da pipe
Se si deve comunicare con un programma esterno utilizzando UTF-8 conviene come al solito memorizzare le stringhe in unicode e quindi esplicitare l'encoding sia per l'input che per l'output:
text = u"ditemi <b>perché</b> se la mucca fa mu..." subproc = subprocess.Popen(["pandoc", "-f", "html", "-t", "LaTeX"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) output, stderr = subproc.communicate(input=text.encode('utf-8')) output = output.decode('utf-8')
La stringa output
sarà di tipo unicode
, al momento di stamparla si dovrà eventualmente decidere (forzare) l'encoding opportuno per evitare conseguenze impreviste (vedi avanti).
Output: codifica implicita della print
Attenzione ad alcuni comportamenti impliciti del Python, ad esempio una semplice
print string
codifica il contenuto di string
in base all'output: se si tratta di stdout
viene usata la codifica utf-8
(per via della variabile d'ambiente LANG=en_US.UTF-8
), se invece si ridirige l'output su file (oppure la variabile LANG
non è impostata correttamente) viene usata la codifica ascii
ed eventualmente scatta l'errore:
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 11: ordinal not in range(128)
Per avere un comportamento univoco conviene codificare esplicitamente l'output:
print string.encode('utf-8')