User Tools

Site Tools


doc:appunti:prog:python_unicode

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
doc:appunti:prog:python_unicode [2012/12/03 11:42] – [Codifica implicita della print] niccolodoc:appunti:prog:python_unicode [2015/07/17 09:50] (current) – [Nomi di file e directory] niccolo
Line 5: Line 5:
 Oppure queste slide: **[[http://farmdev.com/talks/unicode/|Unicode In Python, Completely Demystified]]**. Oppure queste slide: **[[http://farmdev.com/talks/unicode/|Unicode In Python, Completely Demystified]]**.
  
-===== Input: lettura da database =====+===== Input: lettura da database MySQL =====
  
 +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:
 +
 +<code python>
 +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
 +    ...
 +</code>
 +
 +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:
 +
 +<code python>
 +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
 +    ...
 +</code>
 +
 +===== Input/Output: da database PostgreSQL =====
 +
 +Con queste istruzioni si apre una connessione al database e ci si assicura che tutte le stringhe che vengono lette siano di **''<type 'unicode'>''**:
 +
 +<code python>
 +import psycopg2
 +import psycopg2.extensions
 +psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
 +psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
 +
 +conn = psycopg2.connect(host = "127.0.0.1", database = "dbname", user="dbuser", password="dbpass")
 +conn.set_client_encoding("UTF8")
 +curs = conn.cursor()
 +</code>
 +===== 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:
 +
 +<code python>
 +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')
 +</code>
 +
 +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 ===== ===== Output: codifica implicita della print =====
  
Line 15: Line 73:
 </code> </code>
  
-codifica il contenuto di ''string'' in base all'output: se si tratta di ''stdout'' viene usata la codifica **''utf-8''** (per 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:+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:
  
 <code> <code>
Line 27: Line 85:
 </code> </code>
  
 +===== Nomi di file e directory =====
 +
 +Alcune funzioni relative al filesystem potrebbero causare problemi, ad esempio:
 +
 +<code python>
 +os.path.isfile(filename)
 +os.stat(filename)
 +</code>
 +
 +potrebbe fallire con:
 +
 +<code>
 +UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 79: ordinal not in range(128)
 +</code>
 +
 +La soluzione è codificare esplicitamente la stringa prima di passarla alla funzione:
 +
 +<code python>
 +os.path.isfile(filename.encode('utf-8'))
 +os.stat(filename.encode('utf-8'))
 +</code>
 +
 +===== Lettura file di testo =====
 +
 +Invece della semplice **''open()''** conviene l'omologa **''codecs.open()''**:
 +
 +<code python>
 +import codecs
 +for line in codecs.open("filename.txt", "r", "iso-8859-15", "replace"):
 +    print line.strip()
 +</code>
doc/appunti/prog/python_unicode.1354531370.txt.gz · Last modified: 2012/12/03 11:42 by niccolo