[Python] Encoding e setdefaultencoding
Daniele Varrazzo
piro a develer.com
Mar 13 Nov 2007 19:26:55 CET
Cristian Re ha scritto:
> Ecco un esempio che non quadra.
>
> Ora costruiamo la stinga se scrivo:
>
> str = 'perché è così?'
>
> da quel che ho capito ho creato una stringa codificata con codifica
> microsoft "cp1252" giusto?
> per cui se, sempre da console, scrivo "str" e dò invio l'output è ascii
> (codifica di default di python) ed il risultato è:
> 'perch\x82 \x8a cos\x8d?'
I problemi che stai avendo vengono in parte anche dalla console e la shell
interattiva: dalla stringa che mi hai passato vedo che usi una console cp850.
Questo è ciò che succede sulla mia macchina linux con console latin1:
>>> 'perché è così'
'perch\xe9 \xe8 cos\xec'
come vedi i codici delle lettere accentate sono diversi (puoi verificare su
wikipedia alle pagine cp850 e cp1252 che gli encoding sono questi).
Quindi se vuoi creare un literal string unicode dalla tua console interattiva,
devi fare:
'perché è così'.decode('cp850')
Questo però solo in interattivo: prova a scrivere la stessa frase nel tuo
editor di testo, salvarla e leggere il risultato con file('miofile').read().
Possono succedere un paio di cose diverse:
- leggi 'perch\xe9 \xe8 cos\xec': il file è stato salvato in latin1 o in cp1252
- leggi 'perch\xc3\xa9 \xc3\xa8 cos\xc3\xac': il file è stato salvato in utf8
- (molto improbabile) leggi 'perch\x82 \x8a cos\x8d': cp850, ormai lo
sappiamo, ma non conosco nessun editor che lo faccia di default (cp850 è roba
DOS!)
Tutto molto ambiguo, vero? Lo è: infatti se tu il literal che hai scritto
nell'interattivo provi a scriverlo in un file sorgente .py, l'interprete ti
farà una partaccia nel momento in cui eseguirai il file:
piro a kaa ~ $ echo 'a = "perché è così"' > foo.py
piro a kaa ~ $ python foo.py
File "foo.py", line 1
SyntaxError: Non-ASCII character '\xe9' in file foo.py on line 1, but no
encoding declared; see http://www.python.org/peps/pep-0263.html for details
Se un file sorgente Python non contiene solo caratteri ascii (con ord(c) <=
127), allora devi specificare esplicitamente l'encoding che hai usato nel
file, usando la sintassi suggerita nella url del cazziatone :)
>
> mentre se scrivo "print str" la scritta viene visualizzata come quando
> la digito perché l'output è microsoft per cui "cp1252" ok?
Questo perché sia in input che in output (meno male!) la console è cp850,
quindi le due supposizioni sbagliate si annullano ("poggio e buca fa piano") :)
> Se invece volessi crearmi una stringa unicode dovrei utilizzare
> "unicode" specificando che l'input è "cp1252" ma se faccio così:
>
> "str=unicode('perché è così', 'cp1252')"
>
> mi da questo errore:
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> File "C:\Python25\lib\encodings\cp1252.py", line 15, in decode
> return codecs.charmap_decode (input,errors,decoding_table)
> UnicodeDecodeError: 'charmap' codec can't decode byte 0x8d in position
> 12: character maps to <undefined>
>
> mentre se scrivo "str=unicode('perché è così', 'latin-1')" non da
> errore. Non ci sto capendo più nulla però.
Perché appunto il 12mo carattere (0x8d) non è un carattere cp1252 esistente
(vedi tabella su wikipedia). Invece unicode('perché è così', 'cp850') dovrebbe
funzionare. E' strano che 'latin1' non dia errore perché lo stesso carattere
non è definito neanche in questo encoding.
> ora se ridigito da console "str" l'output sembra una stringa unicode:
> u'perch\x82 \x8a cos\x8d'
>
> ma se scrivo print str da questo errore nel file "cp850":
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> File "C:\Python25\lib\encodings\cp850.py", line 12, in encode
> return codecs.charmap_encode(input,errors,encoding_map)
> UnicodeEncodeError: 'charmap' codec can't encode character u'\x82' in
> position 5: character maps to <undefined>
Infatti è una stringa unicode, ma siccome hai fatto il decode col codec
sbagliato, i caratteri unicode creati non sono quelli che ti aspetti. E credo
sfiga voglia che hai beccato esattamente dei caratteri inesistenti! (perché
unicode coincide con latin1 per i primi 256 codepoint, quindi quelli da 0x79 a
0x9F non sono definiti)
> Mi sono perso anche nella spiegazione, latin-1, cp1252, cp850... non so
> più nemmeno cosa stavo chiedendo.
> Avete idea di qualche sito che spiega bene e semplicemente la codifica
> con python?
Il problema non è strettamente Python: sono un macello le codifiche e basta.
Un impiccio extra per te è la console interattiva, che probabilmente non ha lo
stesso encoding dei file che crei con un editor windows qualunque.
I problemi cominciano a diminuire quando:
- conosci l'encoding di input,
- ottieni una stringa unicode facendo il decode() giusto
- lavori con unicode
- quando devi scrivere in un consumatore che consuma stream 8 bit,
conosci l'encoding che desidera
- fai l'encode() del tuo unicode come lo vuole il consumatore e glielo passi.
Dimmi se ti ho chiarito qualcosa o ti ho fatto venire voglia di darti
all'apicultura :)
Per favore, se rispondi a questo messaggio, scrivi sotto alle frasi a cui vuoi
rispondere, non sopra, altrimenti diventa difficile seguire il discorso ;)
Ciao!
--
Daniele Varrazzo - Develer S.r.l.
http://www.develer.com
Maggiori informazioni sulla lista
Python