Por que UTF-8 e não ASCII para o Português? (PARTE I)
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 ab
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 theLANG
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 thecodecs
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/