Maison  >  Article  >  développement back-end  >  Analyse approfondie du codage Python

Analyse approfondie du codage Python

黄舟
黄舟original
2017-07-18 13:27:421009parcourir

On dit que tous ceux qui développent Python sont confus par le problème du codage des caractères. Les erreurs les plus courantes sont UnicodeEncodeError et UnicodeDecodeError. Vous semblez savoir comment les résoudre. Malheureusement, les erreurs apparaissent à d'autres endroits, et le problème. Je répète toujours la même erreur, il est très difficile de se rappeler s'il faut utiliser la méthode de décodage ou d'encodage pour convertir str en Unicode. Je suis toujours confus. Où est le problème ?

Afin de clarifier ce problème, j'ai décidé de mener une analyse approfondie de la composition des chaînes python et des détails du codage des caractères

Octets et caractères

Tout stockés dans l'ordinateur Les données, les caractères de texte, les images, les vidéos, les audios et les logiciels sont tous composés d'une séquence de 01 octets. Un octet est égal à 8 bits.

Un caractère est un symbole. Par exemple, un caractère chinois, une lettre anglaise, un chiffre et un point de ponctuation peuvent tous être appelés un caractère.

Les octets sont pratiques pour le stockage et la transmission réseau, tandis que les caractères sont utilisés pour l'affichage et faciles à lire. Par exemple, le caractère "p" stocké sur le disque dur est une chaîne de données binaires 01110000, occupant un octet de longueur

Codage et décodage

Le texte que nous ouvrons avec l'éditeur , on voit un caractère, ils sont tous stockés sous la forme d'une séquence d'octets binaires lorsqu'ils sont finalement enregistrés sur le disque. Ensuite, le processus de conversion des caractères en octets est appelé codage, et l'inverse est appelé décodage. Les deux sont des processus réversibles. Le codage est destiné au stockage et à la transmission, et le décodage est destiné à l'affichage et à la lecture.

Par exemple, le caractère "p" est codé et enregistré sur le disque dur sous la forme d'une séquence d'octets binaires 01110000, occupant un octet de longueur. Le caractère « Zen » peut être stocké sous la forme « 11100111 10100110 10000101 » occupant une longueur de 3 octets. Pourquoi est-ce possible ? Nous en reparlerons plus tard.

Pourquoi le codage Python est-il si pénible ? Bien entendu, cela ne peut pas être imputé aux développeurs.

En effet, Python2 utilise le codage de caractères ASCII comme codage par défaut et ASCII ne peut pas gérer le chinois, alors pourquoi ne pas utiliser UTf-8 ? Parce que papa Guido a écrit la première ligne de code pour Python à l'hiver 1989, et que la première version a été officiellement open source et publiée en février 1991, et Unicode a été publié en octobre 1991, ce qui signifie que le langage Python a été créé. 8 n’était pas encore né, donc celui-ci en faisait partie.

Python divise également les types de chaînes en deux types, unicode et str, ce qui déroute les développeurs. C'est la deuxième raison. Python3 a complètement remodelé les chaînes, ne conservant qu'un seul type. C'est une histoire pour plus tard.

str et unicode

Python2 divise les chaînes en deux types : unicode et str. Essentiellement, str est une séquence d'octets binaires. Comme le montre l'exemple de code ci-dessous, le "Zen" de type str est imprimé en hexadécimal xecxf8 et la séquence d'octets binaires correspondante est "11101100 11111000".

>>> s = '禅'
>>> s
'\xec\xf8'
>>> type(s)
<type &#39;str&#39;>

Le symbole Unicode correspondant du type Unicode u"Zen" est u'u7985′

>>> u = u"禅"
>>> u
u&#39;\u7985&#39;
>>> type(u)
<type &#39;unicode&#39;>

Si nous voulons enregistrer le symbole Unicode dans un fichier ou le transférer vers le réseau, nous devons passer par Le processus d'encodage est converti en type str, donc python fournit la méthode d'encode pour convertir d'Unicode en str et vice versa.

encode

>>> u = u"禅"
>>> u
u&#39;\u7985&#39;
>>> u.encode("utf-8")
&#39;\xe7\xa6\x85&#39;

decode

>>> s = "禅"
>>> s.decode("utf-8")
u&#39;\u7985&#39;
>>>

De nombreux débutants ne se souviennent pas de la différence entre str et unicode. pour la conversion. Si vous vous souvenez que str est en fait une chaîne de données binaires et qu'unicode est un caractère (symbole), l'encodage (encode) est le processus de conversion de caractères (symboles) en données binaires, donc unicode en str La conversion nécessite le méthode d'encodage, et l'inverse est la méthode de décodage.

encoding always takes a Unicode string and returns a bytes sequence, and decoding always takes a bytes sequence and returns a Unicode string”.

Après avoir clarifié la relation de conversion entre str et unicode, examinons quand les erreurs UnicodeEncodeError et UnicodeDecodeError se produiront.

UnicodeEncodeError

UnicodeEncodeError se produit lorsqu'une chaîne Unicode est convertie en une séquence d'octets str. Examinons un exemple d'enregistrement d'une chaîne de chaînes Unicode dans un fichier

# -*- coding:utf-8 -*-
def main():
    name = u&#39;Python之禅&#39;
    f = open("output.txt", "w")
    f.write(name)
Journal des erreurs

UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 6-7: ordinal not in range(128)
Pourquoi UnicodeEncodeError se produit-il ?


Parce que lors de l'appel de la méthode write, Python déterminera d'abord de quel type est la chaîne. Si elle est str, elle sera écrite directement dans le fichier sans encodage, car la chaîne de type str elle-même est une. chaîne de séquence d’octets binaires.

Si la chaîne est de type Unicode, elle appellera d'abord la méthode encode pour convertir la chaîne Unicode en type str binaire avant de l'enregistrer dans le fichier. La méthode encode utilisera le code ascii par défaut de Python pour encoder<.>

équivaut à :

Cependant, nous savons que le jeu de caractères ASCII ne contient que 128 lettres latines, à l'exclusion des caractères chinois, donc le codec 'ascii' ne peut pas encoder les caractères semble être une erreur . Pour utiliser correctement l'encodage, vous devez spécifier un jeu de caractères contenant des caractères chinois, tels que UTF-8, GBK.
>>> u"Python之禅".encode("ascii")

Donc, pour écrire correctement des chaînes Unicode dans des fichiers, vous devez au préalable convertir les chaînes en codage UTF-8 ou GBK.
>>> u"Python之禅".encode("utf-8")
&#39;Python\xe4\xb9\x8b\xe7\xa6\x85&#39;

>>> u"Python之禅".encode("gbk")
&#39;Python\xd6\xae\xec\xf8&#39;
def main():
    name = u&#39;Python之禅&#39;
    name = name.encode(&#39;utf-8&#39;)
    with open("output.txt", "w") as f:
        f.write(name)

当然,把 unicode 字符串正确地写入文件不止一种方式,但原理是一样的,这里不再介绍,把字符串写入数据库,传输到网络都是同样的原理

UnicodeDecodeError

UnicodeDecodeError 发生在 str 类型的字节序列解码成 unicode 类型的字符串时

>>> a = u"禅"
>>> a
u&#39;\u7985&#39;
>>> b = a.encode("utf-8")
>>> b
&#39;\xe7\xa6\x85&#39;
>>> b.decode("gbk")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: &#39;gbk&#39; codec can&#39;t decode byte 0x85 in position 2: incomplete multibyte sequence

把一个经过 UTF-8 编码后生成的字节序列 ‘\xe7\xa6\x85′ 再用 GBK 解码转换成 unicode 字符串时,出现 UnicodeDecodeError,因为 (对于中文字符)GBK 编码只占用两个字节,而 UTF-8 占用3个字节,用 GBK 转换时,还多出一个字节,因此它没法解析。避免 UnicodeDecodeError 的关键是保持 编码和解码时用的编码类型一致。

这也回答了文章开头说的字符 “禅”,保存到文件中有可能占3个字节,有可能占2个字节,具体处决于 encode 的时候指定的编码格式是什么。

再举一个 UnicodeDecodeError 的例子

>>> x = u"Python"
>>> y = "之禅"
>>> x + y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: &#39;ascii&#39; codec can&#39;t decode byte 0xe4 in position 0: ordinal not in range(128)
>>>

str 与 unicode 字符串 执行 + 操作是,Python 会把 str 类型的字节序列隐式地转换成(解码)成 和 x 一样的 unicode 类型,但Python是使用默认的 ascii 编码来转换的,而 ASCII 中不包含中文,所以报错了。

>>> y.decode(&#39;ascii&#39;)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: &#39;ascii&#39; codec can&#39;t decode byte 0xe4 in position 0: ordinal not in range(128)

正确地方式应该是显示地把 y 用 UTF-8 或者 GBK 进行解码。

>>> x = u"Python"
>>> y = "之禅"
>>> y = y.decode("utf-8")
>>> x + y
u&#39;Python\u4e4b\u7985&#39;

以上内容都是基于 Python2 来讲的,关于 Python3 的字符和编码将会另开一篇文章来写,保持关注。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn