UnicodeDecodeError: Kodek „utf8” nie może zdekodować bajtu 0x9c

289

Mam serwer gniazd, który powinien odbierać prawidłowe znaki UTF-8 od klientów.

Problem polega na tym, że niektórzy klienci (głównie hakerzy) wysyłają nad nim niewłaściwe dane.

Mogę z łatwością rozróżnić oryginalnego klienta, ale loguję do plików wszystkie przesłane dane, aby móc je później przeanalizować.

Czasami dostaję takie postacie, œktóre powodują UnicodeDecodeErrorbłąd.

Muszę być w stanie utworzyć ciąg UTF-8 z tymi znakami lub bez nich.


Aktualizacja:

W moim szczególnym przypadku usługa gniazda była MTA i dlatego oczekuję tylko otrzymania poleceń ASCII, takich jak:

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

Logowałem to wszystko w JSON.

Potem niektórzy ludzie bez dobrych intencji postanowili sprzedać wszelkiego rodzaju śmieci.

Dlatego w moim konkretnym przypadku jest całkowicie okazywanie usuwania znaków spoza ASCII.

transilvlad
źródło
1
czy ciąg wychodzi z pliku lub gniazda? czy możesz podać przykłady kodowania łańcucha dekodowanego na końcu przed wysłaniem go przez moduł obsługi gniazd / plików?
devsnd
Czy napisałem, czy nie napisałem, że sznur przechodzi przez gniazdo? Po prostu czytam ciąg z gniazda i za pomocą, aby umieścić go w słowniku, a następnie JSON, aby go wysłać. Funkcja JSON nie powiodła się z powodu tych znaków.
transilvlad
czy możesz podać przykładowe dane problemu
Shubham Sharma,

Odpowiedzi:

343

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

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

lub

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

Uwaga: Spowoduje to usunięcie (zignorowanie) znaków, które zwracają ciąg bez nich.

Dla mnie jest to idealny przypadek, ponieważ używam go jako ochrony przed danymi wejściowymi innymi niż ASCII, co nie jest dozwolone przez moją aplikację.

Alternatywnie: Użyj metody open z codecsmodułu, aby wczytać plik:

import codecs
with codecs.open(file_name, 'r', encoding='utf-8',
                 errors='ignore') as fdata:
transilvlad
źródło
45
Tak, chociaż jest to zwykle zła praktyka / niebezpieczna, ponieważ po prostu stracisz postacie. Lepiej określić lub wykryć kodowanie ciągu wejściowego i najpierw odkodować go do Unicode, a następnie zakodować jako UTF-8, na przykład:str.decode('cp1252').encode('utf-8')
Ben Hoyt,
W niektórych przypadkach tak masz rację, może to powodować problemy. W moim przypadku nie przejmuję się nimi, ponieważ wydają się być dodatkowymi znakami pochodzącymi ze złego formatowania i programowania klientów łączących się z moim serwerem gniazd.
transilvlad
Ten naprawdę pomaga, jeśli treść ciągu jest rzeczywiście nieprawidłowa, w moim przypadku, '\xc0msterdam'który zamienia się w u'\ufffdmsterdam'zamień
PvdL
3
jeśli skończyłeś tutaj, ponieważ masz problemy z odczytaniem pliku, otwarcie pliku w trybie binarnym może pomóc: open(file_name, "rb")a następnie zastosuj podejście Bena z powyższych komentarzy
Kristian
ta sama opcja dotyczy jeszcze więcej, np. „coś.decode ()”
Alexander Stohr
83

Zmiana silnika z C na Python załatwiła sprawę.

Silnik to C:

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

Kodek „utf-8” nie może dekodować bajtu 0x92 na pozycji 18: nieprawidłowy bajt początkowy

Silnik to Python:

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

Brak błędów dla mnie.

Doğuş
źródło
3
to właściwie dobre rozwiązanie. nie wiem, dlaczego został odrzucony.
ℕʘʘḆḽḘ
Może to nie być dobry pomysł, jeśli masz ogromny csvplik. Może to prowadzić do OutOfMemorybłędu lub automatycznego ponownego uruchomienia jądra notebooka. Powinieneś ustawić encodingw tej sprawie.
LucasBr
1
Doskonała odpowiedź. Dziękuję Ci. To zadziałało dla mnie. Miałem „?” Wewnątrz postaci w kształcie rombu, która była przyczyną problemu. Z prostymi oczami miałem „” ”, który jest calowy. Zrobiłem dwie rzeczy, żeby to rozgryźć. a) df = pd.read_csv ('test.csv', n_rows = 10000). Działa to idealnie bez silnika. Więc zwiększyłem n_rows, aby dowiedzieć się, który wiersz zawiera błąd. b) df = pd.read_csv ('test.csv', engine = 'python'). To zadziałało i wydrukowałem błędny wiersz za pomocą df.iloc [36145], to wydrukowało mi błędny zapis.
Jagannath Banerjee
1
to też działało dla mnie ... Nie jestem pewien, co się dzieje „pod maską” i czy to rzeczywiście dobre / dobre / właściwe rozwiązanie we wszystkich przypadkach, ale dla mnie to
załatwiło
1
Świetne rozwiązanie! Dziękuję bardzo.
Pechi
62

Ten rodzaj problemu pojawia się teraz, kiedy przeniosłem się do Python 3. Nie miałem pojęcia, że ​​Python 2 po prostu paruje problemy z kodowaniem plików.

Znalazłem to miłe wyjaśnienie różnic i jak znaleźć rozwiązanie, gdy żadne z powyższych nie działało dla mnie.

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

Krótko mówiąc, aby Python 3 zachowywał się tak bardzo, jak to możliwe, użyj Python 2:

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

Jednak przeczytaj artykuł, nie ma jednego rozmiaru dla wszystkich rozwiązań.

James McCormac
źródło
29
>>> '\x9c'.decode('cp1252')
u'\u0153'
>>> print '\x9c'.decode('cp1252')
œ
Ignacio Vazquez-Abrams
źródło
16
Jestem zdezorientowany, jak wybrałeś CP1252? To działało dla mnie, ale dlaczego? Nie wiem i teraz się zgubiłem:. Czy mógłbyś opracować? Wielkie dzięki ! :)
Cyril N.
4
Czy możesz przedstawić opcję, która działa dla wszystkich postaci? Czy istnieje sposób na wykrycie znaków, które należy zdekodować, aby zaimplementować bardziej ogólny kod? Widzę, że wiele osób na to patrzy i założę się, że odrzucenie nie jest pożądaną opcją, jak to jest dla mnie.
transilvlad
Jak widać, pytanie to ma dość dużą popularność. Myślisz, że możesz rozszerzyć swoją odpowiedź o bardziej ogólne rozwiązanie?
transilvlad
13
Nie ma bardziej ogólnego rozwiązania „Zgadnij ruletkę kodującą”
Puppy
5
znalazłem to, używając kombinacji wyszukiwania w sieci, szczęścia i intuicji: cp1252 wasused by default in the legacy components of Microsoft Windows in English and some other Western languages
bolov
24

Miałem ten sam problem UnicodeDecodeErrori rozwiązałem go za pomocą tej linii. Nie wiem, czy to najlepszy sposób, ale mi się udało.

str = str.decode('unicode_escape').encode('utf-8')
maiky_forrester
źródło
13

pierwszy, używając get_encoding_type, aby uzyskać typ pliku kodowania:

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

drugi, otwieranie plików typu:

open(current_file, 'r', encoding = get_encoding_type, errors='ignore')
Ivan Lee
źródło
1
co się stanie, gdy powróci Brak
Chop Labalagun
3

Na wypadek, gdyby ktoś miał ten sam problem. Używam vim z YouCompleteMe , nie udało mi się uruchomić ycmd z tym komunikatem o błędzie, co zrobiłem to: export LC_CTYPE="en_US.UTF-8"problem zniknął.

cykl roboczy
źródło
2
Jak to się ma do tego pytania?
transilvlad
1
Dokładnie tak samo, jeśli wiesz, jak działasz. Wtyczka Ycm to architektura gniazda, komunikacja między klientem a serwerem korzysta z gniazda, oba są modułami Pythona, nie są w stanie dekodować pakietów, jeśli ustawienie kodowania jest nieprawidłowe
cykl roboczy
Mam ten sam problem. Czy możesz mi powiedzieć, gdzie umieścić export LC_CTYPE="en_US.UTF-8"?
Reman
@Remonn cześć, wiesz, że mamy plik profilu dla bash? Włóż do środka.
cykl workplaylif
@hylepo, jestem w systemie Windows :)
Reman
3

Co możesz zrobić, jeśli chcesz zmienić plik, ale nie znasz jego kodowania? Jeśli wiesz, że kodowanie jest zgodne z ASCII i chcesz tylko zbadać lub zmodyfikować części ASCII, możesz otworzyć plik za pomocą procedury obsługi błędów surrogateescape:

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

Rozwiązałem ten problem, dodając

df = pd.read_csv(fileName,encoding='latin1')
Talha Rasool
źródło