Quelle est la différence entre encoder / décoder?

180

Je n'ai jamais été sûr de comprendre la différence entre le décodage et l'encodage str / unicode.

Je sais que str().decode()c'est lorsque vous avez une chaîne d'octets dont vous savez qu'elle a un certain codage de caractères, étant donné ce nom de codage, elle renverra une chaîne unicode.

Je sais que unicode().encode()convertit les caractères unicode en une chaîne d'octets selon un nom de codage donné.

Mais je ne comprends pas ce que str().encode()et unicode().decode()sont pour. Quelqu'un peut-il expliquer et peut-être aussi corriger tout ce que je me suis trompé ci-dessus?

ÉDITER:

Plusieurs réponses donnent des informations sur ce que .encodefait une chaîne, mais personne ne semble savoir ce que .decodefait pour unicode.

ʞɔıu
la source
Je pense que la deuxième réponse de cette page est suffisamment claire et concise.
Ben

Réponses:

106

La decodeméthode des chaînes Unicode n'a vraiment aucune application (à moins que vous n'ayez des données non textuelles dans une chaîne Unicode pour une raison quelconque - voir ci-dessous). Il est principalement là pour des raisons historiques, je pense. Dans Python 3, il a complètement disparu.

unicode().decode()effectuera un encodage implicite de l' sutilisation du codec par défaut (ascii). Vérifiez ceci comme ceci:

>>> 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)

Les messages d'erreur sont exactement les mêmes.

Pour str().encode()c'est l'inverse - il tente un implicite décodage d' savec l'encodage par défaut:

>>> 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)

Utilisé comme ça, str().encode()est également superflu.

Mais il y a une autre application de cette dernière méthode qui est utile: il y a des encodages qui n'ont rien à voir avec les jeux de caractères, et peuvent donc être appliqués aux chaînes de 8 bits de manière significative:

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

Vous avez raison, cependant: l'utilisation ambiguë du "codage" pour ces deux applications est ... maladroite. Encore une fois, avec des types séparés byteet stringdans Python 3, ce n'est plus un problème.


la source
4
.decode()sur les chaînes Unicode pourrait être utile, par exemple,print u'\\u0203'.decode('unicode-escape')
jfs
Bon exemple @JFSebastian en python3 Je suppose que vous feriez:print u'\\u0203'.encode('utf8').decode('unicode-escape')
AJP
1
@AJP: sur Python 3:codecs.decode(u'\\u0203', 'unicode-escape')
jfs
@hop: oui. Pour détecter une entrée invalide et pour la compatibilité Python 2/3, la chaîne peut être encodée explicitement en utilisant l' asciiencodage:\\u0203\u00e4'.encode('ascii').decode('unicode-escape')
jfs
@hop: votre premier commentaire (Pourquoi l'avez-vous supprimé? Ne supprimez pas les commentaires auxquels vous avez répondu) l'a déjà dit. Ma réponse ( .encode('ascii').decode('unicode-escape')) ne dépend pas de sys.getdefaultencoding().
jfs
71

Représenter une chaîne Unicode sous forme de chaîne d'octets est appelé encodage . Utilisez u'...'.encode(encoding).

Exemple:

    >>> 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: le codec 'ascii' ne peut pas encoder les caractères en position 0-5: 
    ordinal hors de portée (128)

Vous encodez généralement une chaîne Unicode chaque fois que vous devez l'utiliser pour les E / S, par exemple la transférer sur le réseau ou l'enregistrer dans un fichier disque.

La conversion d'une chaîne d'octets en chaîne Unicode est appelée décodage . Utilisez unicode('...', encoding)ou '...'. Décoder (encodage).

Exemple:

   >>> u'æøå '
   u '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5' # l'interpréteur imprime l'objet unicode comme ceci
   >>> 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'

Vous décodez généralement une chaîne d'octets chaque fois que vous recevez des données de chaîne du réseau ou d'un fichier disque.

Je pense qu'il y a quelques changements dans la gestion d'unicode dans python 3, donc ce qui précède n'est probablement pas correct pour python 3.

Quelques bons liens:

codeape
la source
6
Vous n'avez pas répondu à la question du PO. OP veut savoir ce que font str.encode () et unicode.decode (). Vous venez de répéter ce qui était dit dans la question initiale.
coincé le
Excellente réponse pour savoir pourquoi, dans la pratique, vous vous embêtez avec le décodage et l'encodage. Toutes les machines ne comprennent pas le même jeu de caractères, mais elles comprennent toutes les octets. Encodez en octets pour un langage que les ordinateurs comprennent universellement (et peut être transféré ou enregistré sur le disque), mais décodez lorsque les humains doivent réellement lire ces octets (par exemple du côté client).
Alex Petralia
Réponse fantastique! Cela devrait augmenter !!
sandyp
16

anUnicode. encode ('encoding') donne un objet string et peut être appelé sur un objet unicode

un string. decode ('encoding') donne un objet unicode et peut être appelé sur une chaîne, encodée dans un encodage donné.


Quelques explications supplémentaires:

Vous pouvez créer un objet Unicode, qui n'a pas de jeu de codage. La façon dont il est stocké par Python en mémoire ne vous concerne pas. Vous pouvez le rechercher, le diviser et appeler n'importe quelle fonction de manipulation de chaîne de votre choix.

Mais il arrive un moment où vous souhaitez imprimer votre objet Unicode sur la console ou dans un fichier texte. Vous devez donc l' encoder (par exemple - en UTF-8), vous appelez encode ('utf-8') et vous obtenez une chaîne avec '\ u <someNumber>' à l'intérieur, qui est parfaitement imprimable.

Ensuite, encore une fois - vous aimeriez faire le contraire - lisez la chaîne encodée en UTF-8 et traitez-la comme un Unicode, de sorte que \ u360 ne soit qu'un caractère, pas 5. Ensuite, vous décodez une chaîne (avec l'encodage sélectionné) et obtenir un tout nouvel objet de type unicode.

Juste comme note latérale - vous pouvez sélectionner un encodage pervers, comme 'zip', 'base64', 'rot' et certains d'entre eux seront convertis de chaîne en chaîne, mais je pense que le cas le plus courant est celui qui implique UTF-8 / UTF-16 et chaîne.

Abgan
la source
12

mybytestring.encode (somecodec) est significatif pour ces valeurs de somecodec:

  • base64
  • bz2
  • zlib
  • hexadécimal
  • quopri
  • pourriture13
  • string_escape
  • uu

Je ne sais pas à quoi sert le décodage d'un texte Unicode déjà décodé. Essayer cela avec n'importe quel encodage semble toujours essayer d'encoder d'abord avec l'encodage par défaut du système.

nosklo
la source
5

Il existe quelques encodages qui peuvent être utilisés pour dés / encoder de str en str ou d'Unicode en Unicode. Par exemple base64, hex ou même rot13. Ils sont répertoriés dans le module des codecs .

Éditer:

Le message de décodage sur une chaîne unicode peut annuler l'opération d'encodage correspondante:

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

Le type renvoyé est str au lieu d'unicode, ce qui est regrettable à mon avis. Mais quand vous ne faites pas un encodage / décodage correct entre str et unicode, cela ressemble de toute façon à un désordre.


la source
1
-1: la méthode de décodage n'est pas appliquée à l'objet unicode. Au lieu de cela, l'objet Unicode est encodé comme une chaîne d'octets «ascii», avant le début de l'opération de décodage. Pour une preuve de cette assertion, essayez u'ã'.decode ('hex') - qui donne UnicodeEncodeError
nosklo
2
@nosklo: Vous avez raison. Ce que je voulais vraiment dire, c'est que les objets Unicode ont une méthode decode () afin que vous puissiez également leur appliquer des codecs sans encodage de caractères. Toute cette activité sans encodage de caractères rend cette interface un désordre en Python <3.
1

La réponse simple est qu'ils sont exactement le contraire l'un de l'autre.

L'ordinateur utilise l'unité très basique d'octet pour stocker et traiter les informations; cela n'a aucun sens pour les yeux humains.

Par exemple, '\ xe4 \ xb8 \ xad \ xe6 \ x96 \ x87' est la représentation de deux caractères chinois, mais l'ordinateur ne sait (c'est-à-dire imprimer ou stocker) que ce sont des caractères chinois lorsqu'ils reçoivent un dictionnaire pour les rechercher. Mot chinois, dans ce cas, il s'agit d'un dictionnaire "utf-8", et il ne parviendrait pas à afficher correctement le mot chinois voulu si vous regardez dans un dictionnaire différent ou erroné (en utilisant une méthode de décodage différente).

Dans le cas ci-dessus, le processus permettant à un ordinateur de rechercher un mot chinois est decode().

Et le processus d'écriture par ordinateur du chinois dans la mémoire de l'ordinateur est encode().

Ainsi, les informations codées sont les octets bruts, et les informations décodées sont les octets bruts et le nom du dictionnaire à référencer (mais pas le dictionnaire lui-même).

Baie d'Eren
la source