Um outro post que fiz na Python-Brasil:
Os colegas já falaram sobre o por quê do UTF-8.
Eu gostaria apenas de lembrar que o assunto é mais complicado do que parece, por exemplo no Python 2.7:
# -*- coding: utf-8 -*-
print "Acentos: áéíóúãõç"
print u"Acentos2: áéíóúãõç"
Execute o programa acima no Windows, pode ser pelo IDLE ou pelo console:
C:\Users\nilo\Desktop>\Python27\python.exe test.py
Acentos: ├í├®├¡├│├║├º├ú├Á
Acentos2: áéíóúçãõ
Você deve ter obtido bons resultados apenas na linha do Acentos2. Se a string não é marcada com unicode, vai ser simplesmente impressa como uma sequência de bytes, sem tradução. Se tiver o u na frente, como em acentos2, o Python saca que precisa traduzir de unicode para cp850, no caso do console aqui de casa. Já no Linux, as duas linhas produzem resultados corretos!
O encoding: utf-8 informa apenas a codificação do código fonte. Ou seja, é apenas uma dica de como os caracteres deveriam estar codificados. Para que funcione corretamente, seu editor de texto tem que estar configurado para UTF-8 também. Se misturar, é desastre na certa. Eu recomendo o PSPad no Windows para editar com UTF-8. Para verificar o encoding de um arquivo que você não conhece, ou para ter certeza de qual codificação seu editor realmente utilizou, use um visualizador binário como o HxD [3]. No hex edit do PS Pad, atenção que ele mostra os caracteres em Unicode, mesmo se a codificação for UTF-8. Isso para lembrar que UTF-8 é uma representação ou forma de codificação de caracteres Unicode. O Notepad++ pode também ser usado para editar e codificar arquivos em UTF-8.
No Mac e no Linux, tente o hexdump -C arquivo
Quando o arquivo esta codificado corretamente em utf-8, você deve ter mais de um byte para os caracteres acentuados.
Por exemplo, o programa acima, criado no vim do Ubuntu:
nilo@linuxvm:~$ hexdump -C test.py
00000000 23 20 2d 2a 2d 20 63 6f 64 69 6e 67 3a 20 20 75 |# -*- coding: u|
00000010 74 66 2d 38 20 2d 2a 2d 0a 70 72 69 6e 74 20 22 |tf-8 -*-.print "|
00000020 41 63 65 6e 74 6f 73 3a 20 c3 a1 c3 a9 c3 ad c3 |Acentos: .......|
00000030 b3 c3 ba c3 a3 c3 b5 c3 a7 22 0a 70 72 69 6e 74 |.........".print|
00000040 20 22 41 63 65 6e 74 6f 73 32 3a 20 c3 a1 c3 a9 | "Acentos2: ....|
00000050 c3 ad c3 b3 c3 ba c3 a3 c3 b5 c3 a7 22 0a 0a |............"..|
0000005f
Um site bacana é esse aqui: http://www.utf8-chartable.de/
Uma vez resolvido o problema de codificação dos fontes, restam ainda:
* A codificação do console
* A codificação dos arquivos de dados
* Codificação do banco de dados
Tanto o Mac quanto Linux usam UTF-8 por padrão. O Windows usa a cp 1252 (GUI), compatível com iso8859_1. Cuidado também se você troca arquivos entre máquinas Windows, Linux e Mac. E nunca misture duas codificações no mesmo arquivo, pois isto gera erros difíceis de detectar e resolver.
É fácil misturar quando se faz append em um arquivo, vindo de outra máquina ou mesmo gerado em um outro programa.
O Windows em chinês, russo e outras línguas não utilizam a cp1252! Por isso UTF-8 é uma boa pedida, pois consegue codificar caracteres Unicode com um ou vários bytes, dependendo da necessidade.
O Python 3 resolve muito destes problemas, mas a documentação diz[1]:
Files opened as text files (still the default mode for open()) always use an encoding to map between strings (in memory) and bytes (on disk). Binary files (opened with a b in the mode argument) always use bytes in memory. This means that if a file is opened using an incorrect mode or encoding, I/O will likely fail loudly, instead of silently producing incorrect data. It also means that even Unix users will have to specify the correct mode (text or binary) when opening a file. There is a platform-dependent default encoding, which on Unixy platforms can be set with the LANG environment variable (and sometimes also with some other platform-specific locale-related environment variables). In many cases, but not all, the system default is UTF-8; you should never count on this default. Any application reading or writing more than pure ASCII text should probably have a way to override the encoding. There is no longer any need for using the encoding-aware streams in the codecs module.
A parte que sublinhei diz: "... o padrão do sistema é UTF-8; você não deve contar nunca com este padrão..."
Resumindo, é um assunto que merece ser estudado, pois causa problemas "mágicos" que sempre aparecem.
Um texto que explica tudo com detalhes pode ser encontrado em [2].
[]
Nilo Menezes
[1] http://docs.python.org/release/3.0.1/whatsnew/3.0.html
[2] http://wiki.python.org.br/TudoSobrePythoneUnicode
[3] http://mh-nexus.de/en/hxd/