UnicodeDecodeError: Der Codec 'utf8' kann das Byte 0x9c nicht dekodieren

289

Ich habe einen Socket-Server, der gültige UTF-8-Zeichen von Clients empfangen soll.

Das Problem ist, dass einige Clients (hauptsächlich Hacker) die falschen Daten darüber senden.

Ich kann den echten Client leicht unterscheiden, aber ich protokolliere alle gesendeten Daten in Dateien, damit ich sie später analysieren kann.

Manchmal bekomme ich solche Zeichen œ, die den UnicodeDecodeErrorFehler verursachen.

Ich muss in der Lage sein, die Zeichenfolge UTF-8 mit oder ohne diese Zeichen zu erstellen.


Aktualisieren:

Für meinen speziellen Fall war der Socket-Dienst ein MTA und daher erwarte ich nur ASCII-Befehle wie:

EHLO example.com
MAIL FROM: <john.doe@example.com>
...

Ich habe das alles in JSON protokolliert.

Dann beschlossen einige Leute da draußen ohne gute Absichten, alle Arten von Müll zu verkaufen.

Aus diesem Grund ist es für meinen speziellen Fall vollkommen in Ordnung, die Nicht-ASCII-Zeichen zu entfernen.

transilvlad
quelle
1
Kommt die Zeichenfolge aus einer Datei oder einem Socket? Könnten Sie bitte Codebeispiele dafür posten, wie der String codiert und decodiert wird, bevor er über den Socket / Filehandler gesendet wird?
Devsnd
Habe ich geschrieben oder habe ich nicht geschrieben, dass die Zeichenfolge über den Socket kommt? Ich lese einfach den String aus dem Socket und mit, um ihn in ein Wörterbuch zu schreiben und dann JSON, um ihn mitzusenden. Die JSON-Funktion ist aufgrund dieser Zeichen fehlgeschlagen.
Transilvlad
Können

Antworten:

343

http://docs.python.org/howto/unicode.html#the-unicode-type

str = unicode(str, errors='replace')

oder

str = unicode(str, errors='ignore')

Hinweis: Dadurch werden die betreffenden Zeichen entfernt (ignoriert) und die Zeichenfolge ohne sie zurückgegeben.

Für mich ist dies ein idealer Fall, da ich es als Schutz gegen Nicht-ASCII-Eingaben verwende, die von meiner Anwendung nicht zugelassen werden.

Alternativ: Verwenden Sie die Methode open aus dem codecsModul, um die Datei einzulesen:

import codecs
with codecs.open(file_name, 'r', encoding='utf-8',
                 errors='ignore') as fdata:
transilvlad
quelle
45
Ja, obwohl dies normalerweise eine schlechte Übung / gefährlich ist, weil Sie nur Charaktere verlieren. Es ist besser, die Codierung der Eingabezeichenfolge zu bestimmen oder zu erkennen und sie zuerst in Unicode zu decodieren und dann als UTF-8 zu codieren, zum Beispiel:str.decode('cp1252').encode('utf-8')
Ben Hoyt
In einigen Fällen haben Sie Recht, es kann Probleme verursachen. In meinem Fall interessieren sie mich nicht, da es sich anscheinend um zusätzliche Zeichen handelt, die auf die schlechte Formatierung und Programmierung der Clients zurückzuführen sind, die eine Verbindung zu meinem Socket-Server herstellen.
Transilvlad
Dieser hilft tatsächlich, wenn der Inhalt der Zeichenfolge tatsächlich ungültig ist, in meinem Fall, '\xc0msterdam'der sich u'\ufffdmsterdam'mit replace
PvdL
3
Wenn Sie hier gelandet sind, weil Sie Probleme beim Lesen einer Datei haben, kann das Öffnen der Datei im Binärmodus hilfreich sein: open(file_name, "rb")und dann Bens Ansatz aus den obigen Kommentaren anwenden
kristian
Die gleiche Option gilt für noch mehr, z. B. für "Something.decode ()"
Alexander Stohr
83

Das Ändern der Engine von C auf Python hat den Trick für mich getan.

Motor ist C:

pd.read_csv(gdp_path, sep='\t', engine='c')

Der Codec 'utf-8' kann das Byte 0x92 an Position 18 nicht dekodieren: Ungültiges Startbyte

Engine ist Python:

pd.read_csv(gdp_path, sep='\t', engine='python')

Keine Fehler für mich.

Doğuş
quelle
3
Das ist eigentlich eine gute Lösung. Ich weiß nicht, warum es abgelehnt wurde.
15.
Dies könnte keine gute Idee sein, wenn Sie eine große csvDatei haben. Dies kann zu einem OutOfMemoryFehler oder einem automatischen Neustart des Kernels Ihres Notebooks führen. Sie sollten das encodingauf diesen Fall einstellen .
LucasBr
1
Hervorragende Antwort. Danke. Das hat bei mir funktioniert. Ich hatte "?" In einem rautenförmigen Charakter, der das Problem verursachte. Mit einfachen Augen hatte ich "" ", was Zoll ist. Ich habe zwei Dinge getan, um herauszufinden. a) df = pd.read_csv ('test.csv', n_rows = 10000). Dies funktionierte perfekt ohne Motor. Also habe ich die n_rows erhöht, um herauszufinden, welche Zeile einen Fehler hatte. b) df = pd.read_csv ('test.csv', engine = 'python'). Dies funktionierte und ich druckte die fehlerhafte Zeile mit df.iloc [36145]. Dies druckte mir den fehlerhaften Datensatz.
Jagannath Banerjee
1
das hat auch bei mir funktioniert ... Ich bin mir nicht sicher, was "unter der Haube" passiert und ob dies tatsächlich in allen Fällen eine nette / gute / richtige Lösung ist, aber es hat den Trick für mich getan;)
Chrisvdberge
1
Tolle Lösung! Ich danke dir sehr.
Pechi
62

Diese Art von Problem tritt für mich jetzt auf, da ich zu Python 3 gewechselt bin. Ich hatte keine Ahnung, dass Python 2 einfach Probleme mit der Dateicodierung mit Dampf rollt.

Ich fand diese nette Erklärung der Unterschiede und wie man eine Lösung findet, nachdem keines der oben genannten für mich funktioniert hat.

http://python-notes.curiousefficiency.org/en/latest/python3/text_file_processing.html

Kurz gesagt, um Python 3 so ähnlich wie möglich zu Python 2 zu verhalten, verwenden Sie:

with open(filename, encoding="latin-1") as datafile:
    # work on datafile here

Lesen Sie jedoch den Artikel, es gibt keine Einheitslösung.

James McCormac
quelle
29
>>> '\x9c'.decode('cp1252')
u'\u0153'
>>> print '\x9c'.decode('cp1252')
œ
Ignacio Vazquez-Abrams
quelle
16
Ich bin verwirrt, wie hast du cp1252 gewählt? Es hat bei mir funktioniert, aber warum? Ich weiß es nicht und jetzt bin ich verloren: /. Könnten Sie näher darauf eingehen? Vielen Dank ! :)
Cyril N.
4
Könnten Sie eine Option vorstellen, die für alle Charaktere funktioniert? Gibt es eine Möglichkeit, die Zeichen zu erkennen, die dekodiert werden müssen, damit ein allgemeinerer Code implementiert werden kann? Ich sehe, dass viele Leute sich das ansehen und ich wette, dass das Verwerfen nicht die gewünschte Option ist, wie es für mich ist.
Transilvlad
Wie Sie sehen können, ist diese Frage sehr beliebt. Denken Sie, Sie könnten Ihre Antwort mit einer allgemeineren Lösung erweitern?
Transilvlad
13
Es gibt keine allgemeinere Lösung für "Erraten Sie das Codierungs-Roulette"
Welpe
5
fand es mit einer Kombination aus Websuche, Glück und Intuition: cp1252 warused by default in the legacy components of Microsoft Windows in English and some other Western languages
Bolov
24

Ich hatte das gleiche Problem mit UnicodeDecodeErrorund habe es mit dieser Zeile gelöst. Ich weiß nicht, ob das der beste Weg ist, aber es hat bei mir funktioniert.

str = str.decode('unicode_escape').encode('utf-8')
maiky_forrester
quelle
13

Das erste ist Verwenden von get_encoding_type, um den Dateityp der Codierung abzurufen:

import os    
from chardet import detect

# get file encoding type
def get_encoding_type(file):
    with open(file, 'rb') as f:
        rawdata = f.read()
    return detect(rawdata)['encoding']

das zweite, Öffnen der Dateien mit dem Typ:

open(current_file, 'r', encoding = get_encoding_type, errors='ignore')
Ivan Lee
quelle
1
Was passiert, wenn es zurückkehrt
?
3

Nur für den Fall, dass jemand das gleiche Problem hat. Ich verwende vim mit YouCompleteMe und konnte ycmd nicht mit dieser Fehlermeldung starten. Ich habe Folgendes getan: export LC_CTYPE="en_US.UTF-8"Das Problem ist behoben.

Workplaylifecycle
quelle
2
Wie hängt das mit dieser Frage zusammen?
Transilvlad
1
Genau das gleiche, wenn Sie wissen, wie Ihr Komplett funktioniert. Ycm Plugin ist Socket-Architektur, Kommunikation zwischen Client und Server verwendet Socket, beide sind Python-Module, nicht in der Lage, die Pakete zu dekodieren, wenn die Codierungseinstellung falsch ist
Workplaylifecycle
Ich habe das gleiche Problem. Können Sie mir bitte sagen, wo ich es platzieren soll export LC_CTYPE="en_US.UTF-8"?
Reman
@ Remonn Hallo, weißt du, wir haben eine Profildatei für Bash? Reintun.
Workplaylifecycle
@hylepo, ich bin auf einem Windows-System :)
Reman
3

Was können Sie tun, wenn Sie Änderungen an einer Datei vornehmen müssen, aber die Codierung der Datei nicht kennen? Wenn Sie wissen, dass die Codierung ASCII-kompatibel ist und nur die ASCII-Teile untersuchen oder ändern möchten, können Sie die Datei mit dem Surrogateescape-Fehlerbehandler öffnen:

with open(fname, 'r', encoding="ascii", errors="surrogateescape") as f:
    data = f.read()
Kothapati Purandhar Reddy
quelle
0

Ich habe dieses Problem nur durch Hinzufügen gelöst

df = pd.read_csv(fileName,encoding='latin1')
Talha Rasool
quelle