UnicodeDecodeError: Der Codec 'ascii' kann das Byte 0xd1 an Position 2 nicht dekodieren: Ordnungszahl nicht im Bereich (128)

107

Ich versuche, mit einem sehr großen Datensatz zu arbeiten, der einige nicht standardmäßige Zeichen enthält. Ich muss Unicode gemäß den Jobspezifikationen verwenden, bin aber verblüfft. (Und möglicherweise alles falsch machen.)

Ich öffne die CSV mit:

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

Dann versuche ich es zu codieren mit:

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

Ich codiere alles außer lat und lng, weil diese an eine API gesendet werden müssen. Wenn ich das Programm ausführe, um den Datensatz in das zu analysieren, was ich verwenden kann, erhalte ich den folgenden 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)

Ich denke, ich sollte Ihnen sagen, dass ich Python 2.7.2 verwende, und dies ist Teil einer App, die auf Django 1.4 basiert. Ich habe mehrere Beiträge zu diesem Thema gelesen, aber keiner von ihnen scheint direkt zuzutreffen. Jede Hilfe wird sehr geschätzt.

Vielleicht möchten Sie auch wissen, dass einige der nicht standardmäßigen Zeichen, die das Problem verursachen, Ñ und möglicherweise É sind.

Jelkimantis
quelle
1
Was ist Ihre ursprüngliche Dateicodierung? Ich denke, Sie sollten es gemäß der ursprünglichen Codierung dekodieren und dann in utf 8
xiao 2
Ein mögliches Duplikat der Codierung ergibt "'ascii' Codec kann kein Zeichen codieren ... Ordnungszahl nicht im Bereich (128)" [Hrsg.: und von ungefähr einer Million anderen, da bin ich mir sicher.]
Karl Knechtel

Antworten:

152

Unicode ist nicht gleich UTF-8. Letzteres ist nur eine Kodierung für Ersteres.

Du machst es falsch herum. Sie lesen UTF-8- codierte Daten, daher müssen Sie den UTF-8-codierten String in einen Unicode-String decodieren .

So ersetzen Sie einfach .encodemit .decode, und es sollte funktionieren (wenn Ihre CSV - UTF-8-codiert).

Nichts, wofür man sich schämen müsste. Ich wette, 3 von 5 Programmierern hatten Probleme, dies zuerst zu verstehen, wenn nicht mehr;)

Update: Wenn Ihre Eingabedaten nicht UTF-8-codiert sind, müssen Sie .decode()natürlich die entsprechende Codierung verwenden. Wenn nichts angegeben ist, geht Python von ASCII aus, was bei Nicht-ASCII-Zeichen offensichtlich fehlschlägt.

ch3ka
quelle
1
Der Grund für den Fehler ist, dass Python versucht, ihn automatisch von der Standardcodierung ASCII zu dekodieren, damit er ihn dann wie angegeben in UTF-8 codieren kann. Da die Daten kein gültiges ASCII sind, funktioniert es nicht.
agf
7
Sicher, aber wenn es sich um UTF8- codierte Daten handelt (wie ich denke), .decode('utf-8')sollte man dann den Trick machen, noch?
ch3ka
Sicher, du hast wahrscheinlich recht. Ich habe nur erklärt, warum Sie in dieser Situation diesen speziellen Fehler bekommen.
agf
1
Perfekt! Vielen Dank. Es stellt sich also heraus, dass es sich um .decode ('latin-1') handelte - dies ist sinnvoll, weil es Ñ war, das mir das Problem bereitete. Nochmal! Danke dir!
Jelkimantis
Ihre Lösung funktioniert in einigen Fällen, aber wenn ich diese verwende, erhalte ich einen weiteren Fehler: 'ascii' Codec kann das Zeichen u '\ xf1' in Position 2 nicht codieren: Ordnungszahl nicht im Bereich (128)
Vikash Mishra
83

Fügen Sie einfach diese Zeilen zu Ihren Codes hinzu:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
khelili miliana
quelle
5
`AttributeError: Modul 'sys' hat kein Attribut 'setdefaultencoding' scheint in Python 3 nicht zu funktionieren
skjerns
Woot woot! Das hat mir geholfen.
Shougo Makishima
1
Es funktioniert für mein Python 2.7, beachten Sie, dass ein erneutes Laden (sys) erforderlich ist, andernfalls wäre auf setdefaultencoding nicht zugegriffen werden können.
Yu Shen
1
Das war das einzige, was mich aus vielen SO-Fragen heraus zum Laufen gebracht hat. Vielen Dank!
Freedo
Name 'reload' ist nicht definiert
Davide
28

für Python 3 Benutzer. du kannst tun

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

es funktioniert auch mit flasche :)

Skrmnghrd
quelle
1
Es ist das erste Mal, dass ich jemandem hier geholfen habe. fühlt sich gut an zu wissen, dass ich geholfen habe :)
Skrmnghrd
1
Und du hast mir auch geholfen :) Alle anderen Antworten funktionierten nicht beim Lesen von Dateien. Jetzt muss ich herausfinden, wie ich es auch zum Schreiben reparieren kann;)
user2194898
Können Sie mir den Link Ihres Codes senden? Ich werde versuchen zu helfen
Skrmnghrd
9

Der Hauptgrund für den Fehler ist, dass die von Python angenommene Standardcodierung ASCII ist. Wenn die zu codierenden Zeichenfolgendaten encode('utf8')Zeichen enthalten, die außerhalb des ASCII-Bereichs liegen, z. B. für eine Zeichenfolge wie 'hgvcj 파크 파크 387', würde Python einen Fehler auslösen, da die Zeichenfolge nicht das erwartete Codierungsformat aufweist.

Wenn Sie eine frühere Python-Version als Version 3.5 verwenden, besteht eine zuverlässige Lösung darin, die von Python angenommene Standardcodierung auf Folgendes festzulegen utf8:

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

Auf diese Weise kann Python Zeichen innerhalb einer Zeichenfolge antizipieren, die außerhalb des ASCII-Bereichs liegen.

Wenn Sie jedoch Python Version 3.5 oder höher verwenden, ist die Funktion reload () nicht verfügbar, sodass Sie sie mithilfe der Dekodierung beheben müssen, z

name = school_name.decode('utf8').encode('utf8')
Temi Fakunle
quelle
Was ist der Unterschied zwischen Ihrer Antwort und meiner
Khelili Miliana
1
Genauer. Menschen finden kausale Details oft hilfreich. Und Ihr Code funktioniert übrigens, keine Abweichung beabsichtigt.
Temi Fakunle
1
reload ist in Python 3 verfügbar, Sie müssten es nur importieren. von imp import reload
Meow
@Meow, aber es gibt keine sys.setdefaultencoding in Python 3. Im Kontext der Kompatibilität py2 \ py3 reicht also eine Überprüfung aus, sys.getdefaultencoding () vielleicht. Würde mich über einen Ratschlag zu diesem Thema freuen. stackoverflow.com/questions/28127513/…
Konst54
2

Für Python 3-Benutzer:

Das Ändern der Codierung von 'ascii' auf 'latin1' funktioniert.

Sie können auch versuchen, die Codierung automatisch zu finden, indem Sie die oberen 10000 Bytes mithilfe des folgenden Snippets lesen:

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

Mein Computer hatte das falsche Gebietsschema eingestellt.

Ich habe es zuerst getan

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

locale.getpreferredencoding(False)ist die Funktion, die aufgerufen wird, open()wenn Sie keine Codierung angeben . Die Ausgabe sollte sein 'UTF-8', aber in diesem Fall handelt es sich um eine Variante von ASCII .

Dann habe ich den Befehl bash ausgeführt localeund diese Ausgabe erhalten

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

Daher habe ich das Standard-Ubuntu-Gebietsschema verwendet, wodurch Python Dateien als ASCII anstelle von UTF-8 öffnet. Ich musste mein Gebietsschema auf einstellenen_US.UTF-8

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

Wenn Sie das Gebietsschema nicht systemweit ändern können, können Sie Ihren gesamten Python-Code folgendermaßen aufrufen:

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

oder tun

export PYTHONIOENCODING="UTF-8"

Um es in der Shell festzulegen, führen Sie es aus.

Boris
quelle
1

Wenn dieses Problem beim Ausführen von certbot beim Erstellen oder Erneuern des Zertifikats auftritt, verwenden Sie die folgende Methode

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

Dieser Befehl hat das fehlerhafte Zeichen "´" in einer .conf-Datei im Kommentar gefunden. Nach dem Entfernen (Sie können Kommentare nach Belieben bearbeiten) und dem erneuten Laden von Nginx funktionierte alles wieder.

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

Anish Varghese
quelle
0

Wenn Sie sich mit Text in Python befassen, wenn es sich um einen Unicode-Text handelt, notieren Sie sich, dass es sich um Unicode handelt.

Setze text=u'unicode text'stattdessen einfach text='unicode text'.

Das hat in meinem Fall funktioniert.

Prosti
quelle
0

offen mit Codierung UTF 16 wegen lat und long.

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

Es funktioniert, indem nur das Argument 'rb' read binary anstelle von 'r' read verwendet wird

Jose Garcia-Uceda
quelle