Python: el códec 'ascii' no puede decodificar el byte

Estoy realmente confundido. Traté de codificar pero el error decía 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)

Sé cómo evitar el error con el prefijo "u" en la cadena. Me pregunto por qué el error es "no se puede decodificar" cuando se llamó a encode. ¿Qué está haciendo Python bajo el capó?

preguntado el 10 de marzo de 12 a las 05:03

7 Respuestas

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

encode convierte un objeto Unicode en un string objeto. Pero aquí lo has invocado en un string objeto (porque no tienes la u). Entonces Python tiene que convertir el string a una unicode objeto primero. Entonces hace el equivalente de

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

Pero la decodificación falla porque la cadena no es ascii válida. Es por eso que recibe una queja por no poder decodificar.

respondido 10 mar '12, 05:03

¿Entonces, cuál es la solución? Especialmente si no tengo un literal de cadena, solo tengo un objeto de cadena. - Jon Tirsen

@JonTirsen, no deberías estar codificando un objeto de cadena. Un objeto de cadena ya está codificado. Si necesita cambiar la codificación, debe decodificarla en una cadena Unicode y luego codificarla como la codificación deseada. - winston ewert

Entonces, para expresarlo claramente desde arriba, puede "你好".decode('utf-8').encode('utf-8') - deinonychusaurio

@WinstonEwert Supongo que estaba confundido. El negocio de la codificación tiende a dejarme eternamente confundido. Supongo que mi confusión provino de mi propio problema de no saber si la entrada es una cadena o una cadena Unicode y qué codificación puede tener. - deinonychusaurio

@deinonychusaur, sí ... lo entiendo. - winston ewert

Siempre codificar de Unicode a bytes.
En esta dirección, puedes elegir la codificación.

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

La otra forma es decodificar de bytes a Unicode.
En esta dirección, tienes que saber cuál es la codificación.

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

Este punto no se puede enfatizar lo suficiente. Si desea evitar jugar unicode "whack-a-mole", es importante comprender lo que está sucediendo a nivel de datos. Aquí se explica de otra forma:

  • Un objeto Unicode ya está decodificado, nunca querrás llamar decode en ella.
  • Un objeto de cadena de bytes ya está codificado, nunca querrás llamar encode en ella.

Ahora, al ver .encode en una cadena de bytes, Python 2 primero intenta convertirlo implícitamente en texto (un unicode objeto). Del mismo modo, al ver .decode en una cadena Unicode, Python 2 implícitamente intenta convertirlo en bytes (un str objeto).

Estas conversiones implícitas son la razón por la que puede obtener UnicodeDecodeError cuando has llamado encode. Es porque la codificación generalmente acepta un parámetro de tipo unicode; al recibir un str parámetro, hay una decodificación implícita en un objeto de tipo unicode antes de volver a codificarlo con otra codificación. Esta conversión elige un decodificador 'ascii' predeterminado, lo que le da el error de decodificación dentro de un codificador.

De hecho, en Python 3 los métodos str.decode y bytes.encode ni siquiera existen. Su remoción fue un intento [controvertido] de evitar esta confusión común.

... o cualquier codificación sys.getdefaultencoding() menciones; generalmente esto es 'ascii'

Respondido el 16 de diciembre de 16 a las 19:12

Entonces, ¿quiere decir que Python decodifica la cadena de bytes antes de codificar? - thoslin

@thoslin exactamente, agregué más detalles. - wim

¿Qué es _ y por qué faltan paréntesis en sus declaraciones impresas? - Sin errores

@NoBugs 1. en el REPL, _ se refiere al valor anterior 2. porque esta es una pregunta de python-2.x. - wim

Usted puede ensayar lo siguiente

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

Or

También puedes intentar seguir

Agregue la siguiente línea en la parte superior de su archivo .py.

# -*- coding: utf-8 -*- 

contestado el 13 de mayo de 16 a las 09:05

Si está utilizando Python <3, deberá decirle al intérprete que su El literal de cadena es Unicode prefijándolo con 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'

Otras lecturas: CÓMO Unicode.

respondido 10 mar '12, 05:03

Si está codificando una cadena, ¿por qué arroja un error de decodificación? - MXLDevs

@MxLDevs porque no puede obtener un error de decodificación en una acción de codificación. - shleimel

Tu usas u"你好".encode('utf8') para codificar una cadena Unicode. Pero si quieres representar "你好", deberías decodificarlo. Al igual que:

"你好".decode("utf8")

Obtendrás lo que quieras. Quizás debería aprender más sobre codificar y decodificar.

Respondido el 04 de junio de 14 a las 19:06

En caso de que esté tratando con Unicode, a veces en lugar de encode('utf-8'), también puede intentar ignorar los caracteres especiales, p. ej.

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

o como something.decode('unicode_escape').encode('ascii','ignore') como se sugiere aquí.

No es particularmente útil en este ejemplo, pero puede funcionar mejor en otros escenarios cuando no es posible convertir algunos caracteres especiales.

Alternativamente, puede considerar reemplazando un personaje particular usando replace().

contestado el 28 de mayo de 17 a las 17:05

Si está iniciando el intérprete de Python desde un shell en Linux o sistemas similares (BSD, no estoy seguro de Mac), también debe verificar la codificación predeterminada del shell.

Llame al locale charmap desde el shell (no el intérprete de Python) y debería ver

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

Si este no es el caso y ve algo más, p. Ej.

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

Python heredará (al menos en algunos casos, como en el mío) la codificación del shell y no podrá imprimir (¿algunos? ¿Todos?) Caracteres Unicode. La propia codificación predeterminada de Python que ve y controla a través de sys.getdefaultencoding() y sys.setdefaultencoding() en este caso se ignora.

Si encuentra que tiene este problema, puede solucionarlo

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

(O, alternativamente, elija el mapa de teclas que desee en lugar de en_EN). También puede editar /etc/locale.conf (o cualquier archivo que gobierne la definición de configuración regional en su sistema) para corregir esto.

Respondido el 27 de Septiembre de 18 a las 23:09

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.