Trabalhando com Python 2.7, estou me perguntando qual é a vantagem real em usar o tipo em unicode
vez de str
, já que ambos parecem ser capazes de conter strings Unicode. Existe algum motivo especial além de ser capaz de definir códigos Unicode em unicode
strings usando o caractere de escape \
?:
Executando um módulo com:
# -*- coding: utf-8 -*-
a = 'á'
ua = u'á'
print a, ua
Resultados em: á, á
EDITAR:
Mais testes usando o shell Python:
>>> a = 'á'
>>> a
'\xc3\xa1'
>>> ua = u'á'
>>> ua
u'\xe1'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> ua
u'\xe1'
Portanto, a unicode
string parece ser codificada usando em latin1
vez de utf-8
e a string bruta é codificada usando utf-8
? Estou ainda mais confuso agora! : S
unicode
, é apenas uma abstração de caracteres Unicode;unicode
pode ser convertido parastr
com alguma codificação (por exemploutf-8
).Respostas:
unicode
destina-se a lidar com texto . Texto é uma sequência de pontos de código que pode ser maior do que um único byte . O texto pode ser codificado em uma codificação específica para representar o texto como bytes brutos (por exemploutf-8
,latin-1
...).Observe que
unicode
não está codificado ! A representação interna usada pelo python é um detalhe de implementação e você não deve se preocupar com isso, desde que seja capaz de representar os pontos de código que você deseja.Pelo contrário,
str
em Python 2 é uma sequência simples de bytes . Não representa texto!Você pode pensar nisso
unicode
como uma representação geral de algum texto, que pode ser codificado de muitas maneiras diferentes em uma sequência de dados binários representados porstr
.Nota: No Python 3,
unicode
foi renomeado parastr
e há um novobytes
tipo para uma sequência simples de bytes.Algumas diferenças que você pode ver:
Observe que usando
str
você tem um controle de nível inferior nos bytes únicos de uma representação de codificação específica, enquanto usandounicode
você só pode controlar no nível de ponto de código. Por exemplo, você pode fazer:O que antes era UTF-8 válido, não é mais. Usando uma string Unicode, você não pode operar de forma que a string resultante não seja um texto Unicode válido. Você pode remover um ponto de código, substituir um ponto de código por um ponto de código diferente, etc., mas não pode mexer com a representação interna.
fonte
unicode
objetos, acho que primeiro temos que explicitamenteencode()
para o formato de codificação apropriado, já que não sabemos qual está sendo usado internamente para representar ounicode
valor.unicode
objeto.unicode
não está codificada está totalmente errada. UTF-16 / UCS-2 e UTF-32 / UCS-4 também são codificações ... e, no futuro, possivelmente mais dessas serão criadas. O ponto é que, só porque você não deve se preocupar com os detalhes de implementação (e, na verdade, você não deve!), Ainda não significa queunicode
não esteja codificado. É, claro. Se isso pode acontecer.decode()
, é uma história totalmente diferente.unicode
representação interna do objeto pode ser o que ele quiser, inclusive fora do padrão. Em particular em python3 +unicode
se utilizar uma representação interna não padrão que também muda de acordo com os dados contidos. Como tal, não é uma codificação padrão . Unicode como um padrão de texto apenas define pontos de código que são uma representação abstrata de texto, há toneladas de maneiras de codificar unicode na memória, incluindo o utf-X padrão etc. Python usa seu próprio caminho para eficiência.unicode
objeto CPython , uma vez que não usa UTF-16, nem UTF-32. Ele usa uma representação ad hoc e, se você quiser codificar os dados em bytes reais, terá que usarencode
. Além disso: a linguagem não determina comounicode
é implementado, portanto, diferentes versões ou implementações de python podem (e têm ) diferentes representações internas.Unicode e codificações são coisas completamente diferentes e não relacionadas.
Unicode
Atribui um ID numérico a cada caractere:
Portanto, o Unicode atribui o número 0x41 a A, 0xE1 a á e 0x414 a Д.
Até a pequena seta → que usei tem seu número Unicode, é 0x2192. E mesmo os emojis têm seus números Unicode, 😂 é 0x1F602.
Você pode pesquisar os números Unicode de todos os caracteres nesta tabela . Em particular, você pode encontrar os primeiros três caracteres acima aqui , a seta aqui e o emoji aqui .
Esses números atribuídos a todos os caracteres por Unicode são chamados de pontos de código .
O objetivo de tudo isso é fornecer um meio de se referir inequivocamente a cada personagem. Por exemplo, se estou falando sobre 😂, em vez de dizer "você sabe, esse emoji rindo com lágrimas" , posso apenas dizer, ponto de código Unicode 0x1F602 . Mais fácil, certo?
Observe que os pontos de código Unicode geralmente são formatados com um inicial e
U+
, em seguida, o valor numérico hexadecimal preenchido com pelo menos 4 dígitos. Portanto, os exemplos acima seriam U + 0041, U + 00E1, U + 0414, U + 2192, U + 1F602.Os pontos de código Unicode variam de U + 0000 a U + 10FFFF. Isso é 1.114.112 números. 2.048 desses números são usados para substitutos , portanto, permanecem 1.112.064. Isso significa que o Unicode pode atribuir um ID exclusivo (ponto de código) a 1.112.064 caracteres distintos. Nem todos esses pontos de código foram atribuídos a um caractere ainda, e o Unicode é estendido continuamente (por exemplo, quando novos emojis são introduzidos).
O importante a lembrar é que tudo o que o Unicode faz é atribuir um ID numérico, chamado ponto de código, a cada caractere para uma referência fácil e inequívoca.
Codificações
Mapeie caracteres para padrões de bits.
Esses padrões de bits são usados para representar os caracteres na memória do computador ou no disco.
Existem muitas codificações diferentes que abrangem diferentes subconjuntos de caracteres. No mundo de língua inglesa, as codificações mais comuns são as seguintes:
ASCII
Mapas de 128 caracteres (pontos de código U + 0000 a U + 007F) para padrões de bits de comprimento 7.
Exemplo:
Você pode ver todos os mapeamentos nesta tabela .
ISO 8859-1 (também conhecido como Latin-1)
Mapas de 191 caracteres (pontos de código U + 0020 para U + 007E e U + 00A0 para U + 00FF) para padrões de bits de comprimento 8.
Exemplo:
Você pode ver todos os mapeamentos nesta tabela .
UTF-8
Mapas 1.112.064 caracteres (todos os pontos de código Unicode existentes) para padrões de bits de comprimento 8, 16, 24 ou 32 bits (ou seja, 1, 2, 3 ou 4 bytes).
Exemplo:
A maneira como o UTF-8 codifica caracteres para sequências de bits é muito bem descrita aqui .
Unicode e codificações
Observando os exemplos acima, fica claro como o Unicode é útil.
Por exemplo, se eu sou Latin-1 e desejo explicar minha codificação de á, não preciso dizer:
Mas posso apenas dizer:
E se eu for UTF-8 , posso dizer:
E é inequivocamente claro para todos a qual personagem queremos dizer.
Agora, para a confusão que muitas vezes surge
É verdade que às vezes o padrão de bits de uma codificação, se você interpretá-lo como um número binário, é o mesmo que o ponto de código Unicode desse caractere.
Por exemplo:
Claro, isso foi arranjado assim de propósito por conveniência. Mas você deve olhar para isso como uma pura coincidência . O padrão de bits usado para representar um caractere na memória não está vinculado de forma alguma ao ponto de código Unicode desse caractere.
Ninguém diz que você deve interpretar uma string de bits como 11100001 como um número binário. Basta olhar para ele como a sequência de bits que Latin-1 usa para codificar o caractere á .
De volta à sua pergunta
A codificação usada pelo seu interpretador Python é UTF-8 .
Aqui está o que está acontecendo em seus exemplos:
Exemplo 1
O seguinte codifica o caractere á em UTF-8. Isso resulta na sequência de bits 11000011 10100001, que é salva na variável
a
.Quando você olha para o valor de
a
, seu conteúdo 11000011 10100001 é formatado como o número hexadecimal 0xC3 0xA1 e gerado como'\xc3\xa1'
:Exemplo 2
O seguinte salva o ponto de código Unicode de á, que é U + 00E1, na variável
ua
(não sabemos qual formato de dados o Python usa internamente para representar o ponto de código U + 00E1 na memória e isso não é importante para nós):Quando você olha para o valor de
ua
, Python informa que ele contém o ponto de código U + 00E1:Exemplo 3
O seguinte codifica o ponto de código Unicode U + 00E1 (representando o caractere á) com UTF-8, o que resulta no padrão de bits 11000011 10100001. Novamente, para a saída, este padrão de bits é representado como o número hexadecimal 0xC3 0xA1:
Exemplo 4
O seguinte codifica o ponto de código Unicode U + 00E1 (representando o caractere á) com Latin-1, o que resulta no padrão de bits 11100001. Para a saída, este padrão de bits é representado como o número hexadecimal 0xE1, que por coincidência é o mesmo que o inicial ponto de código U + 00E1:
Não há relação entre o objeto Unicode
ua
e a codificação Latin-1. Que o ponto de código de á seja U + 00E1 e a codificação Latin-1 de á seja 0xE1 (se você interpretar o padrão de bits da codificação como um número binário) é pura coincidência.fonte
Acontece que seu terminal está configurado para UTF-8.
O fato de que a impressão
a
funciona é uma coincidência; você está gravando bytes UTF-8 brutos no terminal.a
é um valor de comprimento dois , contendo dois bytes, valores hexadecimais C3 e A1, enquantoua
é um valor Unicode de comprimento um , contendo um ponto de código U + 00E1.Essa diferença de comprimento é um dos principais motivos para usar valores Unicode; você não pode medir facilmente o número de caracteres de texto em uma string de bytes; O
len()
de uma string de byte informa quantos bytes foram usados, não quantos caracteres foram codificados.Você pode ver a diferença quando codifica o valor Unicode para diferentes codificações de saída:
Observe que os primeiros 256 pontos de código do padrão Unicode correspondem ao padrão Latino 1, portanto, o ponto de código U + 00E1 é codificado em Latim 1 como um byte com valor hexadecimal E1.
Além disso, o Python usa códigos de escape em representações de strings Unicode e de bytes semelhantes, e pontos de código baixo que não são ASCII imprimíveis são representados usando
\x..
valores de escape também. É por isso que uma seqüência de caracteres Unicode com um ponto de código entre 128 e 255 olhares apenas como o 1 de codificação Latina. Se você tiver uma string Unicode com pontos de código além de U + 00FF, uma sequência de escape diferente\u....
será usada, com um valor hexadecimal de quatro dígitos.Parece que você ainda não entendeu completamente qual é a diferença entre Unicode e uma codificação. Leia os seguintes artigos antes de continuar:
O mínimo absoluto que todo desenvolvedor de software deve saber absolutamente e positivamente sobre Unicode e conjuntos de caracteres (sem desculpas!) Por Joel Spolsky
O Python Unicode HOWTO
Unicode pragmático por Ned Batchelder
fonte
\xe1
em latim 1.Quando você define a como unicode, os caracteres a e á são iguais. Caso contrário, á conta como dois caracteres. Experimente len (a) e len (au). Além disso, pode ser necessário ter a codificação ao trabalhar com outros ambientes. Por exemplo, se você usar md5, obterá valores diferentes para a e ua
fonte