[python] UnicodeEncodeError: el códec 'ascii' no puede codificar el carácter u '\ xa0' en la posición 20: ordinal no en el rango (128)



8 Answers

¡Este es un punto de dolor unicode clásico de python! Considera lo siguiente:

a = u'bats\u00E0'
print a
 => batsà

Todo bien hasta ahora, pero si llamamos a str (a), veamos qué sucede:

str(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)

Oh, no, eso no le hará ningún bien a nadie. Para corregir el error, codifique los bytes explícitamente con .encode y diga a python qué códec usar:

a.encode('utf-8')
 => 'bats\xc3\xa0'
print a.encode('utf-8')
 => batsà

Voil \ u00E0!

El problema es que cuando llamas a str (), python usa la codificación de caracteres predeterminada para intentar codificar los bytes que le diste, que en su caso a veces son representaciones de caracteres Unicode. Para solucionar el problema, debes decirle a python cómo tratar con la cadena que le das usando .encode ('whatever_unicode'). La mayoría de las veces, deberías estar bien usando utf-8.

Para una exposición excelente sobre este tema, consulte la charla PyCon de Ned Batchelder aquí: http://nedbatchelder.com/text/unipain.html

Question

Tengo problemas para tratar los caracteres Unicode del texto obtenido de diferentes páginas web (en diferentes sitios). Estoy usando BeautifulSoup.

El problema es que el error no siempre es reproducible; a veces funciona con algunas páginas y, a veces, genera un UnicodeEncodeError . Intenté casi todo lo que se me ocurre y, sin embargo, no encontré nada que funcione de manera consistente sin arrojar algún tipo de error relacionado con Unicode.

A continuación, se muestra una de las secciones de código que está causando problemas:

agent_telno = agent.find('div', 'agent_contact_number')
agent_telno = '' if agent_telno is None else agent_telno.contents[0]
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()

Aquí hay una traza de pila producida en ALGUNAS cadenas cuando se ejecuta el fragmento anterior:

Traceback (most recent call last):
  File "foobar.py", line 792, in <module>
    p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 20: ordinal not in range(128)

Sospecho que esto se debe a que algunas páginas (o más específicamente, las páginas de algunos de los sitios) pueden estar codificadas, mientras que otras pueden estar sin codificar. Todos los sitios se basan en el Reino Unido y brindan datos destinados al consumo del Reino Unido, por lo que no hay problemas relacionados con la internalización ni con el texto escrito en otro idioma que no sea el inglés.

¿Alguien tiene alguna idea sobre cómo resolver esto para poder solucionar este problema de forma CONSISTENTE?




Si tiene algo como packet_data = "This is data" , haga esto en la siguiente línea, justo después de inicializar packet_data :

unic = u''
packet_data = unic



De hecho, he descubierto que en la mayoría de mis casos, simplemente eliminar esos personajes es mucho más simple:

s = mystring.decode('ascii', 'ignore')



Siempre pongo el código a continuación en las primeras dos líneas de los archivos de Python:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals



Bueno, probé todo, pero no sirvió de nada, después de buscar en Google me imaginé lo siguiente y me ayudó. Python 2.7 está en uso.

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')



Acabo de usar lo siguiente:

import unicodedata
message = unicodedata.normalize("NFKD", message)

Verifique qué documentación dice al respecto:

unicodedata.normalize (form, unistr) Devuelve el formulario normal para el unistr de cadena Unicode. Los valores válidos para la forma son 'NFC', 'NFKC', 'NFD' y 'NFKD'.

El estándar Unicode define varias formas de normalización de una cadena Unicode, basándose en la definición de equivalencia canónica y equivalencia de compatibilidad. En Unicode, varios caracteres se pueden expresar de varias maneras. Por ejemplo, el carácter U + 00C7 (LETRA MAYÚSCULA LATINA C CON CEDILLA) también se puede expresar como la secuencia U + 0043 (LETRA MAYÚSCULA LATINA) U + 0327 (COMBINACIÓN DE CEDILLA).

Para cada personaje, hay dos formas normales: forma normal C y forma normal D. La forma normal D (NFD) también se conoce como descomposición canónica, y traduce cada carácter en su forma descompuesta. La forma normal C (NFC) primero aplica una descomposición canónica y luego vuelve a componer caracteres precombinados.

Además de estos dos formularios, existen dos formularios normales adicionales basados ​​en la equivalencia de compatibilidad. En Unicode, se admiten ciertos caracteres que normalmente se unificarían con otros caracteres. Por ejemplo, U + 2160 (ROMAN NUMERAL ONE) es realmente lo mismo que U + 0049 (LETRA MAYÚSCULA I). Sin embargo, es compatible en Unicode para la compatibilidad con juegos de caracteres existentes (por ejemplo, gb2312).

La forma normal KD (NFKD) aplicará la descomposición de compatibilidad, es decir, reemplazará todos los caracteres de compatibilidad con sus equivalentes. La forma normal KC (NFKC) primero aplica la descomposición de compatibilidad, seguida por la composición canónica.

Incluso si dos cadenas Unicode están normalizadas y tienen el mismo aspecto para un lector humano, si uno tiene caracteres combinados y el otro no, es posible que no se puedan comparar iguales.

Lo resuelve por mí. Simple y fácil.




Debajo de la solución funcionó para mí, acaba de agregar

u "Cadena"

(representando la cadena como unicode) antes de mi cadena.

result_html = result.to_html(col_space=1, index=False, justify={'right'})

text = u"""
<html>
<body>
<p>
Hello all, <br>
<br>
Here's weekly enterprise enrollment summary report.  Let me know if you have any questions. <br>
<br>
7 Day Summary <br>
<br>
<br>
{0}
</p>
<p>Thanks,</p>
<p>Lookout Data Team</p>
</body></html>
""".format(result_html)



Aquí hay una repetición de algunas otras respuestas llamadas "cop out". Hay situaciones en las que simplemente descartar los molestos personajes / cadenas es una buena solución, a pesar de las protestas expresadas aquí.

def safeStr(obj):
    try: return str(obj)
    except UnicodeEncodeError:
        return obj.encode('ascii', 'ignore').decode('ascii')
    except: return ""

Probándolo:

if __name__ == '__main__': 
    print safeStr( 1 ) 
    print safeStr( "test" ) 
    print u'98\xb0'
    print safeStr( u'98\xb0' )

Resultados:

1
test
98°
98

Sugerencia: ¿podría querer nombrar esta función a toAscii en toAscii lugar? Esa es una cuestión de preferencia.




Agregue la línea siguiente al comienzo de su script (o como segunda línea):

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

Esa es la definición de la codificación de código fuente python. Más información en PEP 263 .




Related