UnicodeDecodeError: el códec 'ascii' no puede decodificar el byte 0xd1 en la posición 2: ordinal no está en el rango (128)

107

Estoy intentando trabajar con un conjunto de datos muy grande que tiene algunos caracteres no estándar. Necesito usar Unicode, según las especificaciones del trabajo, pero estoy desconcertado. (Y posiblemente haciéndolo todo mal).

Abro el CSV usando:

 15     ncesReader = csv.reader(open('geocoded_output.csv', 'rb'), delimiter='\t', quotechar='"')

Luego, intento codificarlo con:

name=school_name.encode('utf-8'), street=row[9].encode('utf-8'), city=row[10].encode('utf-8'), state=row[11].encode('utf-8'), zip5=row[12], zip4=row[13],county=row[25].encode('utf-8'), lat=row[22], lng=row[23])

Estoy codificando todo excepto lat y lng porque deben enviarse a una API. Cuando ejecuto el programa para analizar el conjunto de datos en lo que puedo usar, obtengo el siguiente Traceback.

Traceback (most recent call last):
  File "push_into_db.py", line 80, in <module>
    main()
  File "push_into_db.py", line 74, in main
    district_map = buildDistrictSchoolMap()
  File "push_into_db.py", line 32, in buildDistrictSchoolMap
    county=row[25].encode('utf-8'), lat=row[22], lng=row[23])
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 2: ordinal not in range(128)

Creo que debería decirte que estoy usando python 2.7.2, y esto es parte de una aplicación desarrollada en django 1.4. He leído varias publicaciones sobre este tema, pero ninguna parece aplicarse directamente. Cualquier ayuda será apreciada.

También es posible que desee saber que algunos de los caracteres no estándar que causan el problema son Ñ y posiblemente É.

jelkimantis
fuente
1
¿Cuál es la codificación de su archivo original? Creo que deberías decodificarlo de acuerdo con la codificación original y luego convertirlo a utf 8
xiao 啸
un posible duplicado de Encoding da "El códec 'ascii' no puede codificar el carácter ... ordinal no está en el rango (128)" [Ed .: y de aproximadamente un trillón de otros, también, estoy seguro.]
Karl Knechtel

Respuestas:

152

Unicode no es igual a UTF-8. El último es solo una codificación del primero.

Lo estás haciendo al revés. Está leyendo datos codificados en UTF-8 , por lo que debe decodificar la cadena codificada en UTF-8 en una cadena Unicode.

Así que simplemente reemplácelo .encodecon .decode, y debería funcionar (si su .csv está codificado en UTF-8).

Sin embargo, no hay nada de qué avergonzarse. Apuesto a que 3 de cada 5 programadores tuvieron problemas al principio para entender esto, si no más;)

Actualización: si sus datos de entrada no están codificados en UTF-8, entonces debe hacerlo .decode()con la codificación adecuada, por supuesto. Si no se da nada, python asume ASCII, que obviamente falla en caracteres que no son ASCII.

ch3ka
fuente
1
La razón del error es que Python está tratando de decodificarlo automáticamente de la codificación predeterminada, ASCII, para luego poder codificarlo como él especificó, a UTF-8. Dado que los datos no son ASCII válidos, no funcionan.
agf
7
seguro, pero si se trata de datos codificados en UTF8 (como supongo), entonces .decode('utf-8')debería funcionar, ¿no?
ch3ka
Seguro, probablemente tengas razón. Solo estaba explicando por qué obtiene ese error específico en esta situación.
agf
1
¡Perfecto! Muchas gracias. Entonces resulta que era .decode ('latin-1'); esto tiene sentido porque era Ñ el que me estaba dando el problema. ¡De nuevo! ¡Gracias!
jelkimantis
Su solución funciona para algunos casos, pero en caso de que use esto, obtengo otro error , el códec 'ascii' no puede codificar el carácter u '\ xf1' en la posición 2: ordinal no está en el rango (128)
Vikash Mishra
84

Simplemente agregue estas líneas a sus códigos:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
khelili miliana
fuente
5
`AttributeError: el módulo 'sys' no tiene atributo 'setdefaultencoding' no parece funcionar en Python 3
skjerns
¡Woot woot! Eso me ayudó.
Shougo Makishima
1
Funciona para mi Python 2.7, tenga en cuenta que se necesita recargar (sys), de lo contrario, setdefaultencoding no sería accesible.
Yu Shen
1
Eso fue lo único que hizo que funcionara para mí de muchas preguntas SO. ¡Muchas gracias!
Freedo
el nombre 'recargar' no está definido
Davide
28

para usuarios de Python 3. tu puedes hacer

with open(csv_name_here, 'r', encoding="utf-8") as f:
    #some codes

también funciona con matraz :)

Skrmnghrd
fuente
1
Es la primera vez que ayudo a alguien a pasar por aquí. se siente bien sabiendo que ayudé :)
Skrmnghrd
1
Y también me ayudaste :) Todas las demás respuestas no funcionaron para la lectura de archivos. Ahora necesito averiguar cómo solucionarlo también para escribir;)
user2194898
¿me pueden enviar el enlace de su código? Trataré de ayudar
Skrmnghrd
9

La razón principal del error es que la codificación predeterminada asumida por Python es ASCII. Por lo tanto, si los datos de la cadena que se codificarán encode('utf8')contienen un carácter que está fuera del rango ASCII, por ejemplo, para una cadena como 'hgvcj 터 파크 387', Python arrojaría un error porque la cadena no tiene el formato de codificación esperado.

Si está utilizando una versión de Python anterior a la versión 3.5, una solución confiable sería establecer la codificación predeterminada asumida por Python en utf8:

import sys
reload(sys)
sys.setdefaultencoding('utf8')
name = school_name.encode('utf8')

De esta manera, Python podría anticipar caracteres dentro de una cadena que caen fuera del rango ASCII.

Sin embargo, si está utilizando Python versión 3.5 o superior, la función reload () no está disponible, por lo que tendría que solucionarlo usando decode, por ejemplo

name = school_name.decode('utf8').encode('utf8')
Temi Fakunle
fuente
¿
Cuál
1
Más detallado. Las personas a menudo encuentran útiles los detalles causales. Y su código funciona por cierto, sin intención de derogación.
Temi Fakunle
1
Reload está disponible en Python 3, solo tendría que importarlo. desde la recarga de importación de imp
Miau
@Meow pero no hay sys.setdefaultencoding en Python 3. Entonces, en el contexto de la compatibilidad py2 \ py3, alguna verificación servirá, sys.getdefaultencoding () tal vez. Agradecería un consejo al respecto. stackoverflow.com/questions/28127513/…
Konst54
2

Para usuarios de Python 3:

cambiar la codificación de 'ascii' a 'latin1' funciona.

Además, puede intentar encontrar la codificación automáticamente leyendo los 10000 bytes superiores utilizando el siguiente fragmento:

import chardet  
with open("dataset_path", 'rb') as rawdata:  
            result = chardet.detect(rawdata.read(10000))  
print(result)
Prithvi
fuente
2

Mi computadora tenía la configuración regional incorrecta.

Primero hice

>>> import locale
>>> locale.getpreferredencoding(False)
'ANSI_X3.4-1968'

locale.getpreferredencoding(False)es la función llamada por open()cuando no proporcionas una codificación . La salida debería ser 'UTF-8', pero en este caso es una variante de ASCII .

Luego ejecuté el comando bash localey obtuve esta salida

$ locale
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

Entonces, estaba usando la configuración regional predeterminada de Ubuntu, lo que hace que Python abra archivos como ASCII en lugar de UTF-8. Tuve que poner mi local aen_US.UTF-8

sudo apt install locales 
sudo locale-gen en_US en_US.UTF-8    
sudo dpkg-reconfigure locales

Si no puede cambiar la configuración regional en todo el sistema, puede invocar todo su código Python de esta manera:

PYTHONIOENCODING="UTF-8" python3 ./path/to/your/script.py

o hacer

export PYTHONIOENCODING="UTF-8"

para configurarlo en el shell en el que lo ejecuta.

Boris
fuente
1

Si tiene este problema mientras ejecuta certbot mientras crea o renueva el certificado, utilice el siguiente método

grep -r -P '[^\x00-\x7f]' /etc/apache2 /etc/letsencrypt /etc/nginx

Ese comando encontró el carácter ofensivo "´" en un archivo .conf en el comentario. Después de eliminarlo (puede editar los comentarios como desee) y volver a cargar nginx, todo volvió a funcionar.

Fuente: https://github.com/certbot/certbot/issues/5236

Anish Varghese
fuente
0

O cuando trabaje con texto en Python si es un texto Unicode, tome nota de que es Unicode.

En su text=u'unicode text'lugar, establezca solo text='unicode text'.

Esto funcionó en mi caso.

prosti
fuente
0

abierto con codificación UTF 16 debido a lat y long.

with open(csv_name_here, 'r', encoding="utf-16") as f:
karthik r
fuente
0

Funciona simplemente tomando el argumento 'rb' read binary en lugar de 'r' read

José García-Uceda
fuente