A chave para esses problemas de codificação é entender que existem, em princípio, dois conceitos distintos de "string" : (1) string de caracteres e (2) string / array de bytes. Esta distinção foi ignorada por muito tempo devido à onipresença histórica de codificações com não mais que 256 caracteres (ASCII, Latin-1, Windows-1252, Mac OS Roman, ...): essas codificações mapeiam um conjunto de caracteres comuns para números entre 0 e 255 (ou seja, bytes); a troca relativamente limitada de arquivos antes do advento da web tornou tolerável essa situação de codificações incompatíveis, já que a maioria dos programas poderia ignorar o fato de que havia várias codificações, desde que produzissem texto que permanecesse no mesmo sistema operacional: tais programas simplesmente tratar o texto como bytes (por meio da codificação usada pelo sistema operacional). A visão moderna correta separa adequadamente esses dois conceitos de string, com base nos dois pontos a seguir:
A maioria dos personagens não está relacionada a computadores : pode-se desenhá-los em um quadro-negro, etc., como por exemplo بايثون, 中 蟒 e 🐍. "Caracteres" para máquinas também incluem "instruções de desenho" como, por exemplo, espaços, retorno de carro, instruções para definir a direção da escrita (para árabe, etc.), acentos, etc. Uma lista muito grande de caracteres está incluída no padrão Unicode ; ele cobre a maioria dos personagens conhecidos.
Por outro lado, os computadores precisam representar caracteres abstratos de alguma forma: para isso, eles usam matrizes de bytes (números entre 0 e 255 incluídos), porque sua memória vem em blocos de bytes. O processo necessário que converte caracteres em bytes é chamado de codificação . Assim, um computador requer uma codificação para representar os caracteres. Qualquer texto presente em seu computador é codificado (até que seja exibido), seja ele enviado para um terminal (que espera caracteres codificados de uma forma específica), ou salvo em um arquivo. Para serem exibidos ou "compreendidos" adequadamente (por exemplo, pelo interpretador Python), os fluxos de bytes são decodificados em caracteres. Algumas codificações(UTF-8, UTF-16, ...) são definidos por Unicode para sua lista de caracteres (Unicode, portanto, define uma lista de caracteres e codificações para esses caracteres - ainda há lugares onde se vê a expressão "codificação Unicode" como um forma de se referir ao ubíquo UTF-8, mas essa é uma terminologia incorreta, pois o Unicode fornece várias codificações).
Em resumo, os computadores precisam representar internamente os caracteres com bytes , e o fazem por meio de duas operações:
Codificação : caracteres → bytes
Decodificação : bytes → caracteres
Algumas codificações não podem codificar todos os caracteres (por exemplo, ASCII), enquanto (algumas) codificações Unicode permitem que você codifique todos os caracteres Unicode. A codificação também não é necessariamente exclusiva , porque alguns caracteres podem ser representados diretamente ou como uma combinação (por exemplo, de um caractere base e de acentos).
Observe que o conceito de nova linha adiciona uma camada de complicação , uma vez que pode ser representado por caracteres diferentes (de controle) que dependem do sistema operacional (essa é a razão para o modo de leitura de arquivo de nova linha universal do Python ).
Agora, o que chamei de "caractere" acima é o que o Unicode chama de " caractere percebido pelo usuário ". Um único caractere percebido pelo usuário às vezes pode ser representado em Unicode combinando partes de caracteres (caractere base, acentos, ...) encontrados em diferentes índices na lista Unicode, que são chamados de " pontos de código " - esses pontos de código podem ser combinados para formar um "aglomerado de grafemas". Unicode, portanto, leva a um terceiro conceito de string, feito de uma sequência de pontos de código Unicode, que fica entre as strings de byte e de caracteres, e que está mais próximo do último. Vou chamá-los de " strings Unicode " (como em Python 2).
Enquanto o Python pode imprimir strings de caracteres (percebidos pelo usuário), strings não-byte do Python são essencialmente sequências de pontos de código Unicode , não de caracteres percebidos pelo usuário. Os valores de ponto de código são aqueles usados na sintaxe de string do Python \u
e \U
Unicode. Eles não devem ser confundidos com a codificação de um caractere (e não precisam ter nenhum relacionamento com ele: os pontos de código Unicode podem ser codificados de várias maneiras).
Isso tem uma consequência importante: o comprimento de uma string Python (Unicode) é seu número de pontos de código, que nem sempre é o número de caracteres percebidos pelo usuário : assim s = "\u1100\u1161\u11a8"; print(s, "len", len(s))
(Python 3) dá 각 len 3
apesar de s
ter um único caractere percebido pelo usuário (coreano) caractere (porque é representado com 3 pontos de código - mesmo que não seja necessário, como print("\uac01")
mostra). No entanto, em muitas circunstâncias práticas, o comprimento de uma string é o número de caracteres percebidos pelo usuário, porque muitos caracteres são normalmente armazenados pelo Python como um único ponto de código Unicode.
No Python 2 , strings Unicode são chamadas de… "strings Unicode" ( unicode
tipo, forma literal u"…"
), enquanto matrizes de bytes são "strings" ( str
tipo, onde a matriz de bytes pode, por exemplo, ser construída com literais de string "…"
). No Python 3 , as strings Unicode são simplesmente chamadas de "strings" ( str
tipo, forma literal "…"
), enquanto as matrizes de bytes são "bytes" ( bytes
tipo, forma literal b"…"
). Como consequência, algo como "🐍"[0]
dá um resultado diferente em Python 2 ( '\xf0'
, um byte) e Python 3 ( "🐍"
, o primeiro e único caractere).
Com esses poucos pontos-chave, você deve ser capaz de entender a maioria das questões relacionadas à codificação!
Normalmente, quando você imprime u"…"
em um terminal , você não deve pegar lixo: Python conhece a codificação de seu terminal. Na verdade, você pode verificar qual codificação o terminal espera:
% python
Python 2.7.6 (default, Nov 15 2013, 15:20:37)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print sys.stdout.encoding
UTF-8
Se seus caracteres de entrada puderem ser codificados com a codificação do terminal, o Python fará isso e enviará os bytes correspondentes ao seu terminal sem reclamar. O terminal fará o possível para exibir os caracteres após decodificar os bytes de entrada (na pior das hipóteses, a fonte do terminal não possui alguns dos caracteres e, em vez disso, imprimirá algum tipo de espaço em branco).
Se os caracteres de entrada não puderem ser codificados com a codificação do terminal, isso significa que o terminal não está configurado para exibir esses caracteres. Python irá reclamar (em Python com um uma UnicodeEncodeError
vez que a string de caracteres não pode ser codificada de uma forma que se adapte ao seu terminal). A única solução possível é usar um terminal que pode exibir os caracteres (seja configurando o terminal para que ele aceite uma codificação que possa representar seus caracteres, ou usando um programa de terminal diferente). Isso é importante quando você distribui programas que podem ser usados em diferentes ambientes: as mensagens impressas devem ser representadas no terminal do usuário. Às vezes, é melhor usar strings que contenham apenas caracteres ASCII.
No entanto, quando você redireciona ou canaliza a saída de seu programa, geralmente não é possível saber qual é a codificação de entrada do programa receptor, e o código acima retorna alguma codificação padrão: Nenhum (Python 2.7) ou UTF-8 ( Python 3):
% python2.7 -c "import sys; print sys.stdout.encoding" | cat
None
% python3.4 -c "import sys; print(sys.stdout.encoding)" | cat
UTF-8
A codificação de stdin, stdout e stderr pode, no entanto, ser definida por PYTHONIOENCODING
meio da variável de ambiente, se necessário:
% PYTHONIOENCODING=UTF-8 python2.7 -c "import sys; print sys.stdout.encoding" | cat
UTF-8
Se a impressão para um terminal não produzir o que você espera, você pode verificar se a codificação UTF-8 que você colocou manualmente está correta; por exemplo, seu primeiro caractere ( \u001A
) não pode ser impresso, se não estou enganado .
Em http://wiki.python.org/moin/PrintFails , você pode encontrar uma solução como a seguinte, para Python 2.x:
import codecs
import locale
import sys
# Wrap sys.stdout into a StreamWriter to allow writing unicode.
sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)
uni = u"\u001A\u0BC3\u1451\U0001D10C"
print uni
Para Python 3, você pode verificar uma das perguntas feitas anteriormente no StackOverflow.