Qual é a diferença entre codificar / decodificar?

180

Nunca tive certeza de entender a diferença entre decodificação e codificação str / unicode.

Eu sei que str().decode()é para quando você tem uma seqüência de bytes que você sabe que possui uma determinada codificação de caracteres, dado que o nome da codificação retornará uma seqüência de caracteres unicode.

Eu sei que unicode().encode()converte caracteres unicode em uma seqüência de bytes de acordo com um nome de codificação especificado.

Mas não entendo para que serve str().encode()e unicode().decode()para quê . Alguém pode explicar, e possivelmente também corrigir qualquer outra coisa que eu tenha errado acima?

EDITAR:

Várias respostas fornecem informações sobre o que .encodefaz em uma string, mas ninguém parece saber o que .decodefaz com o unicode.

ʞɔıu
fonte
Penso que a segunda resposta desta página é suficientemente clara e concisa.
Ben

Respostas:

106

O decodemétodo de strings unicode realmente não possui nenhum aplicativo (a menos que você tenha alguns dados que não sejam de texto em uma string unicode por algum motivo - veja abaixo). É principalmente por razões históricas, eu acho. No Python 3, ele desapareceu completamente.

unicode().decode()executará uma codificação implícita do suso do codec padrão (ascii). Verifique isso da seguinte maneira:

>>> s = u'ö'
>>> s.decode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 0:
ordinal not in range(128)

>>> s.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 0:
ordinal not in range(128)

As mensagens de erro são exatamente as mesmas.

Por str().encode()que é o contrário - ele tenta um implícito decodificação de scom a codificação padrão:

>>> s = 'ö'
>>> s.decode('utf-8')
u'\xf6'
>>> s.encode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0:
ordinal not in range(128)

Usado assim, str().encode()também é supérfluo.

Mas há outra aplicação do último método que é útil: existem codificações que nada têm a ver com conjuntos de caracteres e, portanto, podem ser aplicadas a cadeias de 8 bits de maneira significativa:

>>> s.encode('zip')
'x\x9c;\xbc\r\x00\x02>\x01z'

Você está certo: o uso ambíguo de "codificação" para esses dois aplicativos é ... complicado. Novamente, com tipos bytee stringtipos separados em Python 3, isso não é mais um problema.


fonte
4
.decode()em strings Unicode pode ser útil, por exemplo,print u'\\u0203'.decode('unicode-escape')
jfs
Bom exemplo @JFSebastian em python3 Eu acho que você faria:print u'\\u0203'.encode('utf8').decode('unicode-escape')
AJP
1
@AJP: on Python 3:codecs.decode(u'\\u0203', 'unicode-escape')
jfs
@hop: sim. Para detectar entrada inválida e para compatibilidade com Python 2/3, a cadeia pode ser codificada explicitamente usando a asciicodificação:\\u0203\u00e4'.encode('ascii').decode('unicode-escape')
jfs
@hop: seu primeiro comentário (por que você o excluiu? Não exclua os comentários que foram respondidos) já o disse. Minha resposta ( .encode('ascii').decode('unicode-escape')) não depende sys.getdefaultencoding().
precisa
71

Representar uma cadeia unicode como uma cadeia de bytes é conhecido como codificação . Use u'...'.encode(encoding).

Exemplo:

    >>> u'æøå'.encode ('utf8')
    '\ xc3 \ x83 \ xc2 \ xa6 \ xc3 \ x83 \ xc2 \ xb8 \ xc3 \ x83 \ xc2 \ xa5'
    >>> u'æøå'.encode ('latin1')
    '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5'
    >>> u'æøå'.encode ('ascii')
    UnicodeEncodeError: o codec 'ascii' não pode codificar caracteres na posição 0-5: 
    ordinal fora do alcance (128)

Geralmente, você codifica uma cadeia de caracteres unicode sempre que precisar usá-la para E / S, por exemplo, transferi-la pela rede ou salvá-la em um arquivo de disco.

Converter uma sequência de bytes em uma sequência unicode é conhecido como decodificação . Use unicode('...', encoding)ou '...'. Decodifique (codificação).

Exemplo:

   >>> u'æøå '
   u '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5' # o interpretador imprime o objeto unicode da seguinte maneira
   >>> unicode ('\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5', 'latin1')
   u '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5'
   >>> '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5'.decode (' latin1 ')
   u '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5'

Você normalmente decodifica uma sequência de bytes sempre que recebe dados da sequência da rede ou de um arquivo de disco.

Eu acredito que existem algumas mudanças no manuseio unicode no python 3, portanto, o acima exposto provavelmente não está correto para o python 3.

Alguns bons links:

codeape
fonte
6
Você não respondeu à pergunta do OP. O OP quer saber o que str.encode () e unicode.decode () fazem. Você acabou de repetir o que foi afirmado na pergunta original.
stuckintheshuck
Ótima resposta para por que, na prática, você mexeria com decodificação e codificação. Nem toda máquina compreende o mesmo conjunto de caracteres, mas todos eles entendem bytes. Codifique em bytes para uma linguagem que os computadores compreendem universalmente (e podem ser transferidos ou salvos no disco), mas decodifique quando os humanos realmente precisam ler esses bytes (por exemplo, no lado do cliente).
Alex Petralia
Resposta fantástica! Isso deve subir !!
sandyp
16

anUnicode. encode ('encoding') resulta em um objeto string e pode ser chamado em um objeto unicode

uma linha. decode ('encoding') resulta em um objeto unicode e pode ser chamado em uma string, codificada em determinada codificação.


Mais algumas explicações:

Você pode criar algum objeto unicode, que não possui nenhum conjunto de codificação. A maneira como ele é armazenado pelo Python na memória não é da sua conta. Você pode pesquisar, dividir e chamar qualquer função de manipulação de string que desejar.

Mas chega um momento em que você deseja imprimir seu objeto unicode no console ou em algum arquivo de texto. Portanto, você deve codificá- lo (por exemplo - em UTF-8), chamar codificar ('utf-8') e obter uma string com '\ u <someNumber>' dentro, o que é perfeitamente imprimível.

Então, novamente - você gostaria de fazer o oposto - leia a string codificada em UTF-8 e a trate como um Unicode, para que o \ u360 tenha um caractere, não 5. Em seguida, decodifique uma string (com codificação selecionada) e obtenha um novo objeto do tipo unicode.

Apenas como uma observação - você pode selecionar algumas codificações pervertidas, como 'zip', 'base64', 'rot' e algumas delas serão convertidas de string para string, mas acredito que o caso mais comum é o que envolve UTF-8 / UTF-16 e sequência.

Abgan
fonte
12

mybytestring.encode (somecodec) é significativo para estes valores de somecodec:

  • base64
  • bz2
  • zlib
  • hex
  • quopri
  • rot13
  • string_escape
  • uu

Não sei ao certo para que decodificar um texto unicode já decodificado. Tentar isso com qualquer codificação parece sempre tentar codificar primeiro com a codificação padrão do sistema.

nosklo
fonte
5

Existem algumas codificações que podem ser usadas para decodificar / codificar de str para str ou de unicode para unicode. Por exemplo, base64, hex ou rot13. Eles estão listados no módulo de codecs .

Editar:

A mensagem de decodificação em uma cadeia unicode pode desfazer a operação de codificação correspondente:

In [1]: u'0a'.decode('hex')
Out[1]: '\n'

O tipo retornado é str em vez de unicode, o que é lamentável na minha opinião. Mas quando você não está fazendo uma decodificação / decodificação adequada entre str e unicode, isso parece uma bagunça.


fonte
1
-1: o método de decodificação não está sendo aplicado ao objeto unicode. Em vez disso, o objeto unicode está sendo codificado como uma cadeia de caracteres 'ascii', antes do início da operação de decodificação. Para uma prova dessa afirmação, tente u'ã'.decode ('hex') - que produz UnicodeEncodeError
nosklo
2
@nosklo: Você está certo. O que eu realmente quis dizer é que os objetos unicode têm um método decode () para que você possa aplicar codecs sem codificação de caracteres a eles também. Este inteiro não-codificação de caracteres-business torna essa interface a confusão em Python <3.
1

A resposta simples é que eles são exatamente o oposto um do outro.

O computador usa a unidade básica de bytes para armazenar e processar informações; não faz sentido para os olhos humanos.

Por exemplo, '\ xe4 \ xb8 \ xad \ xe6 \ x96 \ x87' é a representação de dois caracteres chineses, mas o computador sabe apenas (significando impressão ou armazenamento) que são caracteres chineses quando recebem um dicionário para procurar por isso. Palavra chinesa, neste caso, é um dicionário "utf-8" e falharia em exibir corretamente a palavra chinesa pretendida se você procurar um dicionário diferente ou errado (usando um método de decodificação diferente).

No caso acima, o processo para um computador procurar a palavra chinesa é decode().

E o processo do computador escrevendo os chineses na memória do computador é encode().

Portanto, as informações codificadas são os bytes brutos, e as informações decodificadas são os bytes brutos e o nome do dicionário para referência (mas não o próprio dicionário).

Eren Bay
fonte