Error de codificación Unicode de Python


104

Estoy leyendo y analizando un archivo XML de Amazon y mientras el archivo XML muestra un ', cuando intento imprimirlo aparece el siguiente error:

'ascii' codec can't encode character u'\u2019' in position 16: ordinal not in range(128) 

Por lo que he leído en línea hasta ahora, el error proviene del hecho de que el archivo XML está en UTF-8, pero Python quiere manejarlo como un carácter codificado en ASCII. ¿Existe una forma sencilla de hacer que el error desaparezca y hacer que mi programa imprima el XML mientras se lee?


Venía a SO para publicar esta pregunta. ¿Existe una manera fácil de desinfectar una cuerda unicode()?
Nick Heiner

Consulte también esta respuesta a una pregunta relacionada: "Python UnicodeDecodeError - ¿Estoy entendiendo mal la codificación?"
tzot

Respuestas:


193

Probablemente, su problema es que lo analizó bien, y ahora está intentando imprimir el contenido del XML y no puede porque hay algunos caracteres Unicode extranjeros. Intente codificar su cadena unicode como ascii primero:

unicodeData.encode('ascii', 'ignore')

la parte 'ignorar' le dirá que se salte esos caracteres. De los documentos de Python:

>>> u = unichr(40960) + u'abcd' + unichr(1972)
>>> u.encode('utf-8')
'\xea\x80\x80abcd\xde\xb4'
>>> u.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
UnicodeEncodeError: 'ascii' codec can't encode character '\ua000' in position 0: ordinal not in range(128)
>>> u.encode('ascii', 'ignore')
'abcd'
>>> u.encode('ascii', 'replace')
'?abcd?'
>>> u.encode('ascii', 'xmlcharrefreplace')
'&#40960;abcd&#1972;'

Es posible que desee leer este artículo: http://www.joelonsoftware.com/articles/Unicode.html , que encontré muy útil como tutorial básico sobre lo que está sucediendo. Después de la lectura, dejará de sentirse como si estuviera adivinando qué comandos usar (o al menos eso me pasó a mí).


1
Estoy tratando de hacer que la siguiente cadena sea segura: 'foo “bar bar” df' (fíjese en las comillas), pero lo anterior todavía me falla.
Nick Heiner

@Rosarch: ¿Cómo falla? ¿mismo error? ¿Y qué regla de manejo de errores usaste?
Scott Stafford

@Rosarch, tu problema probablemente sea anterior. Pruebe este código: # - - coding: latin-1 - - u = u 'foo "bar bar" df' print u.encode ('ascii', 'ignore') Para usted, probablemente estaba convirtiendo su cadena EN unicode dado la codificación que especificó para la secuencia de comandos de Python que arrojó el error.
Scott Stafford

Seguí adelante e hice mi problema en su propia pregunta: stackoverflow.com/questions/3224427/…
Nick Heiner

1
.encode('ascii', 'ignore')pierde datos innecesariamente incluso si el entorno de OP puede admitir caracteres que no son ascii (la mayoría de los casos)
jfs

16

Una mejor solucion:

if type(value) == str:
    # Ignore errors even if the string is not proper UTF-8 or has
    # broken marker bytes.
    # Python built-in function unicode() can do this.
    value = unicode(value, "utf-8", errors="ignore")
else:
    # Assume the value object has proper __unicode__() method
    value = unicode(value)

Si desea leer más sobre por qué:

http://docs.plone.org/manage/troubleshooting/unicode.html#id1


3
No ayuda con el problema de OP: "no se puede codificar el carácter u '\ u2019'" . u'\u2019ya es Unicode.
jfs

6

No codifique la codificación de caracteres de su entorno dentro de su script; imprima texto Unicode directamente en su lugar:

assert isinstance(text, unicode) # or str on Python 3
print(text)

Si su salida se redirige a un archivo (o una tubería); podría usar PYTHONIOENCODINGenvvar, para especificar la codificación de caracteres:

$ PYTHONIOENCODING=utf-8 python your_script.py >output.utf8

De lo contrario, python your_script.pydebería funcionar como es - los valores de localización se utilizan para codificar el texto (en el cheque POSIX: LC_ALL, LC_CTYPE, LANGenvvars - conjunto LANGa una localización UTF-8 si es necesario).

Para imprimir Unicode en Windows, vea esta respuesta que muestra cómo imprimir Unicode en la consola de Windows, en un archivo o usando IDLE .


1

Excelente publicación: http://www.carlosble.com/2010/12/understanding-python-and-unicode/

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

def __if_number_get_string(number):
    converted_str = number
    if isinstance(number, int) or \
            isinstance(number, float):
        converted_str = str(number)
    return converted_str


def get_unicode(strOrUnicode, encoding='utf-8'):
    strOrUnicode = __if_number_get_string(strOrUnicode)
    if isinstance(strOrUnicode, unicode):
        return strOrUnicode
    return unicode(strOrUnicode, encoding, errors='ignore')


def get_string(strOrUnicode, encoding='utf-8'):
    strOrUnicode = __if_number_get_string(strOrUnicode)
    if isinstance(strOrUnicode, unicode):
        return strOrUnicode.encode(encoding)
    return strOrUnicode

0

Puedes usar algo de la forma

s.decode('utf-8')

que convertirá una cadena de bytes codificada en UTF-8 en una cadena Unicode de Python. Pero el procedimiento exacto a usar depende de cómo cargue y analice exactamente el archivo XML, por ejemplo, si nunca accede a la cadena XML directamente, es posible que deba usar un objeto decodificador del codecsmódulo .


Ya está codificado en UTF-8 El error es específicamente: myStrings = deque ([u'Dorf and Svoboda \ u2019s text se basa en las subdisciplinas str ... y Computer Engineering \ u2019s. ']) La cadena está en UTF-8 como puedes ver, pero se enoja por el '\ u2019' interno
Alex B

Oh, está bien, pensé que tenías un problema diferente.
David Z

7
@Alex B: No, la cadena es Unicode, no Utf-8. Para codificarlo como Utf-8 use'...'.encode('utf-8')
sth

0

Escribí lo siguiente para corregir las molestas citas que no son ASCII y forzar la conversión a algo utilizable.

unicodeToAsciiMap = {u'\u2019':"'", u'\u2018':"`", }

def unicodeToAscii(inStr):
    try:
        return str(inStr)
    except:
        pass
    outStr = ""
    for i in inStr:
        try:
            outStr = outStr + str(i)
        except:
            if unicodeToAsciiMap.has_key(i):
                outStr = outStr + unicodeToAsciiMap[i]
            else:
                try:
                    print "unicodeToAscii: add to map:", i, repr(i), "(encoded as _)"
                except:
                    print "unicodeToAscii: unknown code (encoded as _)", repr(i)
                outStr = outStr + "_"
    return outStr

0

Si necesita imprimir una representación aproximada de la cadena en la pantalla, en lugar de ignorar esos caracteres no imprimibles, pruebe el unidecodepaquete aquí:

https://pypi.python.org/pypi/Unidecode

La explicación se encuentra aquí:

https://www.tablix.org/~avian/blog/archives/2009/01/unicode_transliteration_in_python/

Esto es mejor que usar el u.encode('ascii', 'ignore')para una cadena determinada uy puede ahorrarle dolores de cabeza innecesarios si la precisión de los caracteres no es lo que busca , pero aún desea tener legibilidad humana.

Wirawan


-1

Intente agregar la siguiente línea en la parte superior de su secuencia de comandos de Python.

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

-1

Python 3.5, 2018

Si no sabe cuál es la codificación, pero el analizador Unicode tiene problemas, puede abrir el archivo Notepad++y seleccionar en la barra superior Encoding->Convert to ANSI. Entonces puedes escribir tu pitón así

with open('filepath', 'r', encoding='ANSI') as file:
    for word in file.read().split():
        print(word)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.