[Python] Usare Unicode e charset

Manlio Perillo manlio_perillo a libero.it
Mer 2 Dic 2009 18:32:03 CET


Massimo Capanni ha scritto:
> Salve,
> 
>  confesso che ho un po' di timore a postare questo thread,

e perchè mai?

>  per il fatto che sono tre giorni che cerco di capire questo argomento
>  e ad ogni articolo che studio in merito mi sembra di fare un passo indietro
>  su quello che ho imparato.
> 
> Comunque, ecco la mia situazione: Windows Xp e Python 2.4.6
> Tutto e' cominciato ignorando (mea culpa) questo problema:
> 
> Listato [1]
> ---------------------------------
> file = open("prova.txt", "w")
> x = 'àòàòàòàò'

Qui probabilmente dovresti usare una stringa Unicode:
x = u'àòàòàòàò'

> file.write(x)

file.write(x.encode('the_encoding_of_your_choice'))

> file.close()
> ---------------------------------
> 
> e il prompt dei comandi mi risponde con:
> 
> ----------------------------------------
> C:\_DATI\pylab>python prova.py
>   File "prova.py", line 2
> SyntaxError: Non-ASCII character '\xe0' in file prova.py on line 2, but no
> encoding declared; see http://www.python.org/peps/pep-0263.html for
> details
> ----------------------------------------
> 
> Visto che l'interprete mi consiglia di leggere il link relativo nel messaggio
> di errore gli do un'occhiata e provo ad aggiungere :
> 
> # -*- coding: utf-8 -*-
> 

Attenzione che non puoi mettere un encoding a caso.
Deve essere l'encoding effettivamente utilizzato nel file.
Cosa hai usato per editare il file?

Alcuni editor riconoscono quella dichiarazione, e salvano il file usando
l'encoding specificato.

> e tutto funziona.
> 
> Se invece da shell Python scrivo:
> 
> Listato [2]
> ---------------------------------
>>>> x = "ààòàò"
>>>> print x
> ààòàò
>>>> f = open("pippo.txt", "w")
>>>> f.write(x)
>>>> f.close()
> ---------------------------------
> 
> leggendo il file pippo.txt l'output mi stampa:
> 
>> ààòàò
> 
> E qui inziano i miei dubbi.
> 

La shell si comporta in modo diverso.
Infatti, a differenza di quando esegui il codice Python in un file
(modalità batch), in questo caso Python **sa** l'encoding che stai
usando, perchè lo riporta il sistema operativo.


> Anzitutto a quanto ho capito dalla documentazione in giro, Python di
> default utilizza il charset 'ascii', infatti se eseguo queste due istruzioni
> dalla shell ottengo:
> 
>>>> import sys
>>>> sys.getdefaultencoding()
> 'ascii'
> 

Ci sono due informazioni in cui Python ha bisogno di conoscere
l'encoding usato.

Il primo caso è quando, nel listato del programma, hai una string literal.
In questo caso l'encoding è necessario in fase di parsing del programma.

Nel caso in cui l'interprete è eseguito in modalità interattiva, questa
informazione viene ricavata dal sistema operativo.
In modalità batch questa informazione deve essere dichiarata dal
programmatore nel file che contiene il programma.

Il secondo caso è quando converti una stringa normale in Unicode.

>>> byte_string = 'àè'
>>> s = unicode(byte_string)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0:
ordinal not in range(128)

>>> import sys
>>> reload(sys)
<module 'sys' (built-in)>
>>> sys.setdefaultencoding('utf-8')
>>> s = unicode(byte_string)
>>>

Nel mio caso, sono su Linux ed ho il locale impostato a `it_IT.utf8`.


Ci possono essere altri casi; dovrei controllare i sorgenti per
verificare che quanto ho scritto è corretto al 100%.

> [...]
> Provo a fare delle ipotesi:
> 
> ho tre soggetti: il sistema sul quale lavoro, l'editor, Python. Il
> sistema possiede il
> suo charset (ad esempio la cmd di windows mi riporta 437).

Ti conviene utilizzare un altro encoding;
come fare viene spiegato qui:
http://www.postgresql.org/docs/8.4/static/app-psql.html#AEN71654

> [...]



Ciao  Manlio


Maggiori informazioni sulla lista Python