Cómo solucionarlo: “UnicodeDecodeError: el códec ‘ascii’ no puede decodificar el byte”

as3:~/ngokevin-site# nano content/blog/20140114_test-chinese.mkd as3:~/ngokevin-site# wok Traceback (most recent call last): File "/usr/local/bin/wok", line 4, in Engine() File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 104, in init self.load_pages() File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 238, in load_pages p = Page.from_file(os.path.join(root, f), self.options, self, renderer) File "/usr/local/lib/python2.7/site-packages/wok/page.py", line 111, in from_file page.meta['content'] = page.renderer.render(page.original) File "/usr/local/lib/python2.7/site-packages/wok/renderers.py", line 46, in render return markdown(plain, Markdown.plugins) File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 419, in markdown return md.convert(text) File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 281, in convert source = unicode(source) UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 1: ordinal not in range(128). -- Note: Markdown only accepts unicode input! 

¿Como arreglarlo?

En algunas otras aplicaciones de blogs estáticos basados ​​en python, las publicaciones en chino pueden publicarse con éxito. Como esta aplicación: http://github.com/vrypan/bucket3 . En mi sitio http://bc3.brite.biz/ , la publicación china se puede publicar con éxito.

Finalmente lo tengo:

 as3:/usr/local/lib/python2.7/site-packages# cat sitecustomize.py # encoding=utf8 import sys reload(sys) sys.setdefaultencoding('utf8') 

Dejame revisar:

 as3:~/ngokevin-site# python Python 2.7.6 (default, Dec 6 2013, 14:49:02) [GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> reload(sys)  >>> sys.getdefaultencoding() 'utf8' >>> 

Lo anterior muestra que la encoding predeterminada de python es utf8 . Entonces el error ya no existe.

No use la respuesta popular ( sys.setdefaultencoding('utf8') )

Es un hack desagradable (hay una razón por la que tiene que usar la reload ) que solo enmascarará los problemas y dificultará su migración a Python 3.x. Comprenda el problema, arregle la causa raíz y disfrute de Unicode zen. Consulte ¿Por qué NO debemos usar sys.setdefaultencoding (“utf-8”) en un script py? para mas detalles

tl; dr / solución rápida

  • No decodifique / codifique willy nilly
  • No asum que sus cadenas están codificadas en UTF-8
  • Intente convertir cadenas a cadenas Unicode lo antes posible en su código
  • Arregle su ubicación: ¿Cómo resolver UnicodeDecodeError en Python 3.6?

Unicode Zen en Python 2.x – La versión larga

Sin ver la fuente, es difícil saber la causa raíz, así que tendré que hablar en general.

UnicodeDecodeError: 'ascii' codec can't decode byte generalmente ocurre cuando intenta convertir una str Python 2.x que contiene una cadena no ASCII a Unicode sin especificar la encoding de la cadena original.

En resumen, las cadenas de caracteres Unicode son un tipo de cadena de Python completamente independiente que no contiene ninguna encoding. Solo tienen códigos de puntos Unicode y, por lo tanto, pueden contener cualquier punto Unicode de todo el espectro. Las cadenas contienen texto codificado, beit UTF-8, UTF-16, ISO-8895-1, GBK, Big5, etc. Las cadenas se decodifican en Unicode y las Unicodes se codifican en cadenas . Los archivos y los datos de texto siempre se transfieren en cadenas codificadas.

Los autores del módulo Markdown probablemente utilicen unicode() (donde se lanza la excepción) como puerta de acceso al rest del código; convertirá ASCII o volverá a envolver las cadenas Unicodes existentes en una nueva cadena Unicode. Los autores de Markdown no pueden saber la encoding de la cadena entrante, por lo que dependerán de usted para decodificar cadenas a cadenas Unicode antes de pasar a Markdown.

Las cadenas Unicode se pueden declarar en su código usando el prefijo u para cadenas. P.ej

 >>> my_u = u'my ünicôdé strįng' >>> type(my_u)  

Las cadenas Unicode también pueden provenir de archivos, bases de datos y módulos de red. Cuando esto sucede, no necesita preocuparse por la encoding.

Gotchas

La conversión de str a Unicode puede ocurrir incluso cuando no se llama explícitamente a unicode() .

Los siguientes escenarios causan excepciones de UnicodeDecodeError :

 # Explicit conversion without encoding unicode('€') # New style format string into Unicode string # Python will try to convert value string to Unicode first u"The currency is: {}".format('€') # Old style format string into Unicode string # Python will try to convert value string to Unicode first u'The currency is: %s' % '€' # Append string to Unicode # Python will try to convert string to Unicode first u'The currency is: ' + '€' 

Ejemplos

En el siguiente diagtwig, puede ver cómo la palabra café se ha codificado en encoding “UTF-8” o “Cp1252” según el tipo de terminal. En ambos ejemplos, caf es ascii regular. En UTF-8, é se codifica utilizando dos bytes. En “Cp1252”, é es 0xE9 (que también es el valor del punto Unicode (no es una coincidencia)). Se invoca la decode() correcta decode() y la conversión a un Unicode de Python es exitosa: Diagrama de una cadena que se convierte en una cadena Python Unicode

En este diagtwig, se llama a decode() con ascii (que es lo mismo que llamar a unicode() sin una encoding dada). Como ASCII no puede contener bytes mayores que 0x7F , esto generará una excepción UnicodeDecodeError :

Diagrama de una cadena que se convierte en una cadena Python Unicode con la codificación incorrecta

El Sandwich De Unicode

Es una buena práctica formar un sándwich de Unicode en su código, donde decodifique todos los datos entrantes a cadenas de Unicode, trabaje con Unicodes y luego codifique a str s en el camino de salida. Esto le evita preocuparse por la encoding de cadenas en medio de su código.

Entrada / Deencoding

Código fuente

Si necesita hornear no ASCII en su código fuente, simplemente cree cadenas Unicode prefijando la cadena con una u . P.ej

 u'Zürich' 

Para permitir que Python descodifique su código fuente, deberá agregar un encabezado de encoding para que coincida con la encoding real de su archivo. Por ejemplo, si su archivo fue codificado como ‘UTF-8’, usaría:

 # encoding: utf-8 

Esto solo es necesario cuando no tiene ASCII en su código fuente .

Archivos

Por lo general, los datos que no son ASCII se reciben de un archivo. El módulo io proporciona un TextWrapper que decodifica su archivo sobre la marcha, utilizando una encoding dada. Debe utilizar la encoding correcta para el archivo, no se puede adivinar fácilmente. Por ejemplo, para un archivo UTF-8:

 import io with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file: my_unicode_string = my_file.read() 

my_unicode_string sería adecuado para pasar a Markdown. Si un UnicodeDecodeError de la línea read() , entonces probablemente ha usado el valor de encoding incorrecto.

Archivos CSV

El módulo CSV de Python 2.7 no admite caracteres no ASCII 😩. Sin embargo, hay ayuda disponible con https://pypi.python.org/pypi/backports.csv .

Úselo como arriba pero pásele el archivo abierto:

 from backports import csv import io with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file: for row in csv.reader(my_file): yield row 

Bases de datos

La mayoría de los controladores de base de datos de Python pueden devolver datos en Unicode, pero generalmente requieren una pequeña configuración. Siempre use cadenas Unicode para consultas SQL.

MySQL

En la cadena de conexión agregar:

 charset='utf8', use_unicode=True 

P.ej

 >>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8") 

PostgreSQL

Añadir:

 psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY) 

HTTP

Las páginas web se pueden codificar en casi cualquier encoding. El encabezado de Content-type debe contener un campo de juego de charset para indicar la encoding. El contenido puede entonces decodificarse manualmente contra este valor. Como alternativa, Python-Requests devuelve Unicodes en response.text .

A mano

Si debe decodificar cadenas manualmente, simplemente puede hacer my_string.decode(encoding) , donde la encoding es la encoding adecuada. Los códecs compatibles con Python 2.x se proporcionan aquí: Codificaciones estándar . Nuevamente, si obtienes UnicodeDecodeError entonces probablemente tienes la encoding incorrecta.

La carne del sandwich.

Trabaja con Unicodes como lo harías con strs normales.

Salida

stdout / impresión

print escribe a través de la secuencia stdout. Python intenta configurar un codificador en la salida estándar para que los Unicodes estén codificados en la encoding de la consola. Por ejemplo, si la locale un shell de Linux es en_GB.UTF-8 , la salida se codificará como UTF-8 . En Windows, estará limitado a una página de códigos de 8 bits.

Una consola configurada incorrectamente, como una configuración regional dañada, puede provocar errores de impresión inesperados. PYTHONIOENCODING variable de entorno PYTHONIOENCODING puede forzar la encoding de la PYTHONIOENCODING .

Archivos

Al igual que la entrada, io.open se puede usar para convertir de forma transparente Unicodes en cadenas de bytes codificadas.

Base de datos

La misma configuración para la lectura permitirá escribir Unicodes directamente.

Python 3

Python 3 ya no es compatible con Unicode, como lo es Python 2.x, pero la str normal ahora es una cadena Unicode y la str antigua ahora es bytes .

La encoding predeterminada ahora es UTF-8, por lo que si .decode() una cadena de bytes sin dar una encoding, Python 3 usa la encoding UTF-8. Esto probablemente soluciona el 50% de los problemas de Unicode de las personas.

Además, open() opera en modo de texto por defecto, por lo que devuelve str decodificada (Unicode). La encoding se deriva de su configuración regional, que tiende a ser UTF-8 en sistemas Un * x o una página de códigos de 8 bits, como windows-1251, en cuadros de Windows.

Este es el clásico “problema de Unicode”. Creo que explicar esto está más allá del scope de una respuesta de StackOverflow para explicar completamente lo que está sucediendo.

Está bien explicado aquí .

En un breve resumen, ha pasado algo que se interpreta como una cadena de bytes a algo que necesita decodificarlo en caracteres Unicode, pero el códec predeterminado (ascii) está fallando.

La presentación que te señalé proporciona consejos para evitar esto. Haga su código un “sándwich Unicode”. En Python 2, el uso de “from __future__ import unicode_literals” ayuda.

Actualización: cómo se puede arreglar el código:

OK – en tu variable “fuente” tienes algunos bytes. De su pregunta no queda claro cómo llegaron allí. ¿Tal vez los lea de un formulario web? En cualquier caso, no están codificados con ascii, pero Python está intentando convertirlos a Unicode suponiendo que lo están. Necesitas decirle explícitamente qué es la encoding. ¡Esto significa que necesitas saber qué es la encoding! Eso no siempre es fácil, y depende completamente de la procedencia de esta cadena. Podría experimentar con algunas codificaciones comunes, por ejemplo, UTF-8. Le dices a Unicode () la encoding como un segundo parámetro:

 source = unicode(source, 'utf-8') 

En algunos casos, cuando verifica su encoding predeterminada ( print sys.getdefaultencoding() ), devuelve que está usando ASCII. Si cambia a UTF-8, no funcionará, dependiendo del contenido de su variable. Encontré otra manera:

 import sys reload(sys) sys.setdefaultencoding('Cp1252') 
 "UnicodeDecodeError: 'ascii' codec can't decode byte" 

Causa de este error: input_string debe ser unicode pero se dio str

 "TypeError: Decoding Unicode is not supported" 

Causa de este error: intentar convertir unicode input_string en unicode


Entonces, primero verifique que su input_string sea str y conviértase a unicode si es necesario:

 if isinstance(input_string, str): input_string = unicode(input_string, 'utf-8') 

En segundo lugar, lo anterior solo cambia el tipo pero no elimina los caracteres que no son ASCII. Si desea eliminar caracteres no-ascii:

 if isinstance(input_string, str): input_string = input_string.decode('ascii', 'ignore').encode('ascii') #note: this removes the character and encodes back to string. elif isinstance(input_string, unicode): input_string = input_string.encode('ascii', 'ignore') 

Estaba buscando para resolver el siguiente mensaje de error:

unicodedecodeerror: el codec ‘ascii’ no puede decodificar el byte 0xe2 en la posición 5454: ordinal no está en el rango (128)

Finalmente lo arreglé especificando ‘encoding’:

 f = open('../glove/glove.6B.100d.txt', encoding="utf-8") 

Ojalá pudiera ayudarte también.

Creo que lo mejor es convertir siempre a Unicode, pero esto es difícil de lograr porque en la práctica tendrías que revisar y convertir cada argumento a cada función y método que escribas que incluya algún tipo de procesamiento de cadenas.

Así que se me ocurrió el siguiente enfoque para garantizar unicodes o cadenas de bytes, desde cualquier entrada. En resumen, incluya y use las siguientes lambdas:

 # guarantee unicode string _u = lambda t: t.decode('UTF-8', 'replace') if isinstance(t, str) else t _uu = lambda *tt: tuple(_u(t) for t in tt) # guarantee byte string in UTF8 encoding _u8 = lambda t: t.encode('UTF-8', 'replace') if isinstance(t, unicode) else t _uu8 = lambda *tt: tuple(_u8(t) for t in tt) 

Ejemplos:

 text='Some string with codes > 127, like Zürich' utext=u'Some string with codes > 127, like Zürich' print "==> with _u, _uu" print _u(text), type(_u(text)) print _u(utext), type(_u(utext)) print _uu(text, utext), type(_uu(text, utext)) print "==> with u8, uu8" print _u8(text), type(_u8(text)) print _u8(utext), type(_u8(utext)) print _uu8(text, utext), type(_uu8(text, utext)) # with % formatting, always use _u() and _uu() print "Some unknown input %s" % _u(text) print "Multiple inputs %s, %s" % _uu(text, text) # but with string.format be sure to always work with unicode strings print u"Also works with formats: {}".format(_u(text)) print u"Also works with formats: {},{}".format(*_uu(text, text)) # ... or use _u8 and _uu8, because string.format expects byte strings print "Also works with formats: {}".format(_u8(text)) print "Also works with formats: {},{}".format(*_uu8(text, text)) 

Aquí hay un poco más de razonamiento sobre esto .

Codificar convierte un objeto Unicode en un objeto de cadena. Creo que estás tratando de codificar un objeto de cadena. primero convierta su resultado en un objeto Unicode y luego codifique ese objeto Unicode en ‘utf-8’. por ejemplo

  result = yourFunction() result.decode().encode('utf-8') 

Tuve el mismo problema pero no funcionó para Python 3. Seguí esto y resolví mi problema:

 enc = sys.getdefaultencoding() file = open(menu, "r", encoding = enc) 

Debe configurar la encoding cuando esté leyendo / escribiendo el archivo.

Tengo el mismo problema con la cadena “PastelerÃa Mallorca” y resolví con:

 unicode("PastelerÃa Mallorca", 'latin-1') 

En resumen, para garantizar un manejo adecuado de Unicode en Python 2:

  • usa io.open para leer / escribir archivos
  • usar from __future__ import unicode_literals
  • configurar otras entradas / salidas de datos (por ejemplo, bases de datos, red) para usar Unicode
  • Si no puede configurar las salidas a utf-8, convierta su salida para print(text.encode('ascii', 'replace').decode())

Para explicaciones, vea la respuesta detallada de @Alastair McCormack.

En un proyecto Django (1.9.10) / Python UnicodeDecodeError tengo frecuentes excepciones UnicodeDecodeError ; Principalmente cuando trato de alimentar cadenas de Unicode para el registro. Hice una función auxiliar para que los objetos arbitrarios se formatearan básicamente a cadenas ASCII de 8 bits y reemplazando cualquier carácter que no estuviera en la tabla a ‘?’. Creo que no es la mejor solución, pero como la encoding predeterminada es ascii (y no quiero cambiarla), funcionará:

 def encode_for_logging (c, encoding = 'ascii'):
     si isinstance (c, basestring):
         devolver c.encode (encoding, 'reemplazar')
     elif isinstance (c, iterable):
         c_ = []
         para v en c:
             c_.append (encode_for_logging (v, encoding))
         volver c_
     más:
         devolver encode_for_logging (unicode (c))

`

Este error se produce cuando hay algunos caracteres no ASCII en nuestra cadena y estamos realizando operaciones en esa cadena sin la deencoding adecuada. Esto me ayudó a resolver mi problema. Estoy leyendo un archivo CSV con las columnas ID, texto y deencoding de caracteres de la siguiente manera:

 train_df = pd.read_csv("Example.csv") train_data = train_df.values for i in train_data: print("ID :" + i[0]) text = i[1].decode("utf-8",errors="ignore").strip().lower() print("Text: " + text) 

Tuve el mismo error, con direcciones URL que contienen caracteres que no son ASCII (bytes con valores> 128)

 url = url.decode('utf8').encode('utf-8') 

Nota: utf-8, utf8 son simplemente alias. Usar solo ‘utf8’ o ‘utf-8’ debería funcionar de la misma manera

En mi caso, funcionó para mí, en Python 2.7, supongo que esta asignación cambió “algo” en la representación interna de str , es decir, fuerza la deencoding correcta de la secuencia de bytes respaldada en la url y finalmente pone la cadena en un utf. 8 str con toda la magia en el lugar correcto. Unicode en Python es magia negra para mí. Esperanza útil

Para resolver esto en un nivel de sistema operativo en una instalación de Ubuntu, verifique lo siguiente:

 $ locale charmap 

Si lo consigues

 locale: Cannot set LC_CTYPE to default locale: No such file or directory 

en lugar de

 UTF-8 

luego establece LC_CTYPE y LC_ALL esta manera:

 $ export LC_ALL="en_US.UTF-8" $ export LC_CTYPE="en_US.UTF-8" 

Aquí está mi solución, simplemente añada la encoding. with open(file, encoding='utf8') as f

Y debido a que la lectura del archivo de guante llevará mucho tiempo, recomiendo el archivo de guante a un archivo numpy. Cuando el tiempo de netx lea los pesos de incrustación, ahorrará tiempo.

 import numpy as np from tqdm import tqdm def load_glove(file): """Loads GloVe vectors in numpy array. Args: file (str): a path to a glove file. Return: dict: a dict of numpy arrays. """ embeddings_index = {} with open(file, encoding='utf8') as f: for i, line in tqdm(enumerate(f)): values = line.split() word = ''.join(values[:-300]) coefs = np.asarray(values[-300:], dtype='float32') embeddings_index[word] = coefs return embeddings_index # EMBEDDING_PATH = '../embedding_weights/glove.840B.300d.txt' EMBEDDING_PATH = 'glove.840B.300d.txt' embeddings = load_glove(EMBEDDING_PATH) np.save('glove_embeddings.npy', embeddings) 

Enlace completo: https://gist.github.com/BrambleXu/634a844cdd3cd04bb2e3ba3c83aef227

Especifique: # encoding = utf-8 en la parte superior de su archivo de Python, debería solucionar el problema