UnicodeDecodeError: le codec 'ascii' ne peut pas décoder l'octet 0xd1 en position 2: ordinal pas dans la plage (128)

107

J'essaie de travailler avec un très grand ensemble de données contenant des caractères non standard. Je dois utiliser unicode, conformément aux spécifications du travail, mais je suis déconcerté. (Et très probablement tout faire mal.)

J'ouvre le CSV en utilisant:

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

Ensuite, j'essaye de l'encoder avec:

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])

J'encode tout sauf le lat et le lng car ceux-ci doivent être envoyés à une API. Lorsque j'exécute le programme pour analyser l'ensemble de données dans ce que je peux utiliser, j'obtiens le Traceback suivant.

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)

Je pense que je devrais vous dire que j'utilise python 2.7.2, et cela fait partie d'une application construite sur django 1.4. J'ai lu plusieurs articles sur ce sujet, mais aucun d'entre eux ne semble s'appliquer directement. Toute aide sera fortement appréciée.

Vous voudrez peut-être également savoir que certains des caractères non standard à l'origine du problème sont Ñ et éventuellement É.

jelkimantis
la source
1
Quel est votre encodage de fichier d'origine? Je pense que vous devriez le décoder selon le codage d'origine, puis le convertir en utf 8
xiao 啸
une duplication possible de l' encodage donne "le codec 'ascii' ne peut pas encoder le caractère… l'ordinal n'est pas dans la plage (128)" [Ed.: et d'environ un million d'autres aussi, j'en suis sûr.]
Karl Knechtel

Réponses:

152

Unicode n'est pas égal à UTF-8. Ce dernier n'est qu'un encodage pour le premier.

Vous le faites dans le mauvais sens. Vous lisez des données encodées en UTF-8 , vous devez donc décoder la chaîne encodée en UTF-8 en une chaîne Unicode.

Alors remplacez simplement .encode par .decode, et cela devrait fonctionner (si votre .csv est encodé en UTF-8).

Il n'y a pas de quoi avoir honte, cependant. Je parie que 3 programmeurs sur 5 ont eu du mal au début à comprendre cela, sinon plus;)

Mise à jour: si vos données d'entrée ne sont pas encodées en UTF-8, vous devez .decode()bien sûr utiliser l'encodage approprié. Si rien n'est donné, python suppose ASCII, qui échoue évidemment sur les caractères non ASCII.

ch3ka
la source
1
La raison de l'erreur est que Python essaie de le décoder automatiquement à partir du codage par défaut, ASCII, afin qu'il puisse ensuite l'encoder comme il l'a spécifié, en UTF-8. Étant donné que les données ne sont pas ASCII valides, cela ne fonctionne pas.
agf
7
bien sûr, mais si ce sont des données encodées en UTF8 (comme je suppose), alors .decode('utf-8')devrait faire l'affaire, ni?
ch3ka
Bien sûr, vous avez probablement raison. J'expliquais simplement pourquoi vous obtenez cette erreur spécifique dans cette situation.
agf
1
Parfait! Merci beaucoup. Il s'avère donc que c'était .decode ('latin-1') - cela a du sens parce que c'est Ñ qui me posait le problème. Encore! Je vous remercie!
jelkimantis
Votre solution fonctionne dans certains cas, mais au cas où je l'utilise, j'obtiens une autre erreur 'ascii' codec ne peut pas encoder le caractère u '\ xf1' en position 2: ordinal pas dans la plage (128)
Vikash Mishra
84

Ajoutez simplement ces lignes à vos codes:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
khelili miliana
la source
5
`AttributeError: le module 'sys' n'a pas d'attribut 'setdefaultencoding' ne semble pas fonctionner dans Python 3
skjerns
Woot woot! Cela m'a aidé.
Shougo Makishima
1
Cela fonctionne pour mon Python 2.7, notez que le rechargement (sys) est nécessaire, sinon setdefaultencoding ne serait pas accessible.
Yu Shen le
1
C'est la seule chose qui a fait que cela a fonctionné pour moi sur de nombreuses questions SO. Merci beaucoup!
Freedo
le nom 'reload' n'est pas défini
Davide le
28

pour les utilisateurs de Python 3. tu peux faire

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

ça marche aussi avec flask :)

Skrmnghrd
la source
1
C'est la première fois que j'aide quelqu'un ici. se sent bien en sachant que j'ai aidé :)
Skrmnghrd
1
Et vous m'avez aidé aussi :) Toutes les autres réponses ne fonctionnaient pas pour la lecture de fichiers. Maintenant, j'ai besoin de savoir comment le réparer également pour l'écriture;)
user2194898
pouvez-vous m'envoyer le lien de votre code? Je vais essayer d'aider
Skrmnghrd
9

La principale raison de l'erreur est que l'encodage par défaut supposé par python est ASCII. Par conséquent, si la chaîne de données à encoder encode('utf8')contient un caractère qui est en dehors de la plage ASCII, par exemple pour une chaîne comme 'hgvcj 터 파크 387', python générerait une erreur car la chaîne n'est pas dans le format de codage attendu.

Si vous utilisez une version python antérieure à la version 3.5, un correctif fiable serait de définir l'encodage par défaut supposé par python sur utf8:

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

De cette façon, python serait capable d'anticiper les caractères d'une chaîne qui ne relèvent pas de la plage ASCII.

Cependant, si vous utilisez python version 3.5 ou supérieure, la fonction reload () n'est pas disponible, vous devrez donc la corriger en utilisant decode, par exemple

name = school_name.decode('utf8').encode('utf8')
Temi Fakunle
la source
Quelle est la différence entre votre réponse et la mienne
khelili miliana
1
Plus détaillé. Les gens trouvent souvent les détails causaux utiles. Et votre code fonctionne, sans aucune dérogation.
Temi Fakunle
1
reload est disponible dans Python 3 il vous suffirait de l'importer. de imp import reload
Meow
@Meow mais il n'y a pas de sys.setdefaultencoding en Python 3. Donc, dans le contexte de la compatibilité py2 \ py3, une vérification fera l'affaire, sys.getdefaultencoding () peut-être. J'apprécierais un morceau de conseil à ce sujet. stackoverflow.com/questions/28127513/…
Konst54
2

Pour les utilisateurs de Python 3:

changer le codage de «ascii» à «latin1» fonctionne.

En outre, vous pouvez essayer de trouver l'encodage automatiquement en lisant les 10000 premiers octets à l'aide de l'extrait de code ci-dessous:

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

Les paramètres régionaux de mon ordinateur n'étaient pas définis.

J'ai d'abord fait

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

locale.getpreferredencoding(False)est la fonction appelée par open()lorsque vous ne fournissez pas d'encodage . La sortie devrait être 'UTF-8', mais dans ce cas, il s'agit d'une variante de l'ASCII .

Ensuite, j'ai exécuté la commande bash localeet j'ai obtenu cette sortie

$ 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=

Donc, j'utilisais la locale Ubuntu par défaut, ce qui oblige Python à ouvrir les fichiers au format ASCII au lieu de UTF-8. J'ai dû régler ma langue suren_US.UTF-8

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

Si vous ne pouvez pas modifier les paramètres régionaux à l'échelle du système, vous pouvez appeler tout votre code Python comme ceci:

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

ou faire

export PYTHONIOENCODING="UTF-8"

pour le définir dans le shell dans lequel vous l'exécutez.

Boris
la source
1

si vous rencontrez ce problème lors de l'exécution de certbot lors de la création ou du renouvellement du certificat, veuillez utiliser la méthode suivante

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

Cette commande a trouvé le caractère incriminé "´" dans un fichier .conf du commentaire. Après l'avoir supprimé (vous pouvez modifier les commentaires comme vous le souhaitez) et recharger nginx, tout a fonctionné à nouveau.

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

Anish Varghese
la source
0

Ou lorsque vous traitez du texte en Python s'il s'agit d'un texte Unicode, notez qu'il s'agit d'un texte Unicode.

Réglez text=u'unicode text'plutôt juste text='unicode text'.

Cela a fonctionné dans mon cas.

prosti
la source
0

ouvert avec encodage UTF 16 à cause de lat et long.

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

Cela fonctionne en prenant simplement l'argument 'rb' read binary au lieu de 'r' read

José Garcia-Uceda
la source