web-dev-qa-db-fra.com

Python - Le codec 'ascii' ne peut pas décoder d'octet

Je suis vraiment confus. J'ai essayé d'encoder mais l'erreur disait can't decode...

>>> "你好".encode("utf8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

Je sais comment éviter l'erreur avec le préfixe "u" sur la chaîne. Je me demande simplement pourquoi l'erreur est "impossible à décoder" quand l'encodage a été appelé. Que fait Python sous le capot?

106
thoslin
"你好".encode('utf-8')

encode convertit un objet unicode en un objet string. Mais ici vous l'avez invoqué sur un objet string (car vous n'avez pas le u). Donc, python doit d'abord convertir la string en un objet unicode. Donc, cela équivaut à

"你好".decode().encode('utf-8')

Mais le décodage échoue car la chaîne n'est pas valide en ascii. C'est pourquoi vous recevez une plainte concernant l'impossibilité de décoder.

151
Winston Ewert

Toujours encoder de Unicode en octets.
.__ Dans ce sens, vous choisissez l’encodage

>>> u"你好".encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print _
你好

L'autre façon consiste à décoder d'octets en unicode.
Dans cette direction, vous devez savoir ce qu'est l'encodage}.

>>> bytes = '\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print bytes
你好
>>> bytes.decode('utf-8')
u'\u4f60\u597d'
>>> print _
你好

Ce point ne peut pas être assez souligné. Si vous voulez éviter de jouer à l'unicode "whack-a-mole", il est important de comprendre ce qui se passe au niveau des données. Ici, il est expliqué d'une autre manière:

  • Un objet unicode est déjà décodé, vous ne voulez jamais appeler decode dessus.
  • Un objet bytestring est déjà codé, vous ne voulez jamais appeler encode dessus.

Désormais, après avoir vu .encode sur une chaîne d'octets, Python 2 commence par tenter de la convertir implicitement en texte (un objet unicode). De même, en voyant .decode sur une chaîne unicode, Python 2 tente implicitement de la convertir en octets (un objet str). 

Ces conversions implicites expliquent pourquoi vous pouvez obtenir UnicodeDecodeError lorsque vous avez appelé encode. C'est parce que l'encodage accepte généralement un paramètre de type unicode; lors de la réception d'un paramètre str, il y a un décodage implicite dans un objet de type unicode avant de le recoder à l'aide d'un autre encodage. Cette conversion choisit un décodeur 'ascii' par défaut, vous donnant l'erreur de décodage à l'intérieur d'un encodeur.

En fait, dans Python 3, les méthodes str.decode et bytes.encode n'existent même pas. Leur élimination était une tentative [controversée] d'éviter cette confusion commune.

... ou ce que le code sys.getdefaultencoding() mentionne; généralement c'est 'ascii'

48
wim

Vous pouvez essayer ceci  

import sys
reload(sys)
sys.setdefaultencoding("utf-8")

Ou

Vous pouvez également essayer de suivre

Ajoutez la ligne suivante en haut de votre fichier .py.

# -*- coding: utf-8 -*- 
36
Dadaso Zanzane

Si vous utilisez Python <3, vous devrez dire à l'interprète que votre littéral de chaîne est Unicode en le préfixant avec un u :

Python 2.7.2 (default, Jan 14 2012, 23:14:09) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> "你好".encode("utf8")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
>>> u"你好".encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'

Lectures supplémentaires: Unicode HOWTO .

8
Johnsyweb

Vous utilisez u"你好".encode('utf8') pour coder une chaîne unicode . Mais si vous souhaitez représenter "你好", vous devez le décoder. Juste comme:

"你好".decode("utf8")

Vous obtiendrez ce que vous voulez. Peut-être devriez-vous en savoir plus sur l'encodage et le décodage.

3
Qingtian

Si vous utilisez Unicode, parfois, au lieu de encode('utf-8'), vous pouvez également essayer d’ignorer les caractères spéciaux, par exemple.

"你好".encode('ascii','ignore')

ou en tant que something.decode('unicode_escape').encode('ascii','ignore') comme suggéré ici .

Pas particulièrement utile dans cet exemple, mais peut mieux fonctionner dans d'autres scénarios lorsqu'il n'est pas possible de convertir certains caractères spéciaux.

Vous pouvez également envisager de remplacer un caractère particulier par replace() .

3
kenorb

Si vous démarrez l'interpréteur python à partir d'un shell sous Linux ou de systèmes similaires (BSD, vous ne savez pas si Mac), vérifiez également le codage par défaut du shell. 

Appelez locale charmap depuis le shell (pas l’interpréteur python) et vous devriez voir

[user@Host dir] $ locale charmap
UTF-8
[user@Host dir] $ 

Si ce n'est pas le cas et que vous voyez autre chose, par exemple 

[user@Host dir] $ locale charmap
ANSI_X3.4-1968
[user@Host dir] $ 

Python héritera (du moins dans certains cas, comme dans le mien) du codage du shell et ne pourra pas imprimer (certains? Tous?) Des caractères Unicode. Le codage par défaut de Python que vous voyez et contrôlez via sys.getdefaultencoding() et sys.setdefaultencoding() est dans ce cas ignoré.

Si vous constatez que vous avez ce problème, vous pouvez le résoudre en 

[user@Host dir] $ export LC_CTYPE="en_EN.UTF-8"
[user@Host dir] $ locale charmap
UTF-8
[user@Host dir] $ 

(Vous pouvez également éditer le /etc/locale.conf (ou le fichier régissant la définition des paramètres régionaux dans votre système) pour corriger ce problème.

0
0range