UnicodeDecodeError, niepoprawny bajt kontynuacji

257

Dlaczego poniższy element nie działa? i dlaczego to się udaje dzięki kodekowi „latin-1”?

o = "a test of \xe9 char" #I want this to remain a string as this is what I am receiving
v = o.decode("utf-8")

prowadzi do:

 Traceback (most recent call last):  
 File "<stdin>", line 1, in <module>  
 File "C:\Python27\lib\encodings\utf_8.py",
 line 16, in decode
     return codecs.utf_8_decode(input, errors, True) UnicodeDecodeError:
 'utf8' codec can't decode byte 0xe9 in position 10: invalid continuation byte
RuiDC
źródło

Odpowiedzi:

247

W systemie binarnym wygląda jak 0xE9 1110 1001. Jeśli przeczytasz o UTF-8 na Wikipedii , zobaczysz, że po takim bajcie muszą następować dwa formularze 10xx xxxx. Na przykład:

>>> b'\xe9\x80\x80'.decode('utf-8')
u'\u9000'

Ale to tylko mechaniczna przyczyna wyjątku. W tym przypadku masz ciąg, który prawie na pewno jest zakodowany w łacinie 1. Możesz zobaczyć, jak UTF-8 i łacina 1 wyglądają inaczej:

>>> u'\xe9'.encode('utf-8')
b'\xc3\xa9'
>>> u'\xe9'.encode('latin-1')
b'\xe9'

(Uwaga: używam tutaj kombinacji reprezentacji Pythona 2 i 3. Dane wejściowe są poprawne w dowolnej wersji Pythona, ale jest mało prawdopodobne, aby Twój interpreter w Pythonie pokazywał w ten sposób zarówno ciągi Unicode, jak i bajtowe.)

Josh Lee
źródło
2
Dzięki (i temu drugiemu, który odpowiedział), miałem błędne przekonanie, że znaki do 255 będą konwertowane bezpośrednio.
RuiDC
UnicodeEncodeError: 'ascii' codec can't encode characters in position 2-3: ordinal not in range(128).encode(latin-1)
Shiva,
234

Miałem ten sam błąd, gdy próbowałem otworzyć plik csv metodą pandas read_csv.

Rozwiązaniem była zmiana kodowania na „latin-1”:

pd.read_csv('ml-100k/u.item', sep='|', names=m_cols , encoding='latin-1')
Mazen Aly
źródło
1
Czy to jednak faktycznie rozwiązuje problem? Czy to po prostu nie mówi pandom, aby ignorowały bajt, obniżając kod do mniej złożonego stylu kodowania?
Yu Chen
61

Jest nieprawidłowy UTF-8. Ten znak jest e-ostrym znakiem w ISO-Latin1 i dlatego odnosi sukces z tym zestawem kodów.

Jeśli nie znasz zestawu kodów, w którym otrzymujesz ciągi, masz trochę problemów. Byłoby najlepiej, gdyby dla twojego protokołu / aplikacji wybrano jeden zestaw kodów (mam nadzieję, że UTF-8), a następnie odrzuciłbyś te, które nie zostały zdekodowane.

Jeśli nie możesz tego zrobić, potrzebujesz heurystyki.

Sami J. Lehtinen
źródło
2
A heurystykę można znaleźć w bibliotece chardet.
mlissner
44

Ponieważ UTF-8 jest wielobajtowy i nie ma znaku odpowiadającego kombinacji \xe9plus spacji.

Dlaczego miałby odnosić sukcesy zarówno w UTF-8, jak i Latin-1?

Oto, jak powinno wyglądać to samo zdanie w utf-8:

>>> o.decode('latin-1').encode("utf-8")
'a test of \xc3\xa9 char'
neurino
źródło
Latin-1 to rodzina kodowania jednobajtowego, więc wszystko w nim powinno być zdefiniowane w UTF-8. Ale dlaczego wygrywa Latin-1?
Reihan_amn
11

Jeśli ten błąd pojawia się podczas manipulowania właśnie otwartym plikiem, sprawdź, czy otworzyłeś go w 'rb'trybie

Patrick Mutuku
źródło
2
Dzięki tej odpowiedzi, był w stanie uniknąć błędu, UnicodeDecodeError: „utf-8” kodek nie może dekodować bajt 0xd7 w pozycji 2024079: nieprawidłowy kontynuacja bajt przez soup = BeautifulSoup(open('webpage.html', 'rb'), 'html.parser')
Isaac Philip
6

To samo mi się przydarzyło, gdy czytałem z .txtpliku tekst zawierający hebrajski .

Kliknąłem: file -> save asi zapisałem ten plik jako UTF-8kodowanie

Alon Gouldman
źródło
5

Błąd kodu utf-8 zwykle pojawia się, gdy zakres wartości liczbowych przekracza od 0 do 127.

powodem podniesienia tego wyjątku jest:

1) Jeśli punkt kodowy ma wartość <128, każdy bajt jest taki sam jak wartość punktu kodowego. 2) Jeśli punktem kodowym jest 128 lub więcej, łańcuch Unicode nie może być reprezentowany w tym kodowaniu. (W tym przypadku Python zgłasza wyjątek UnicodeEncodeError.)

Aby temu zaradzić, mamy zestaw kodowań, najczęściej stosowanym jest „Latin-1, znany również jako ISO-8859-1”

Tak więc punkty Unicode 0–255 ISO-8859-1 są identyczne z wartościami Latin-1, więc konwersja do tego kodowania wymaga po prostu konwersji punktów kodowych na wartości bajtowe; jeśli napotkamy punkt kodowy większy niż 255, ciąg nie może być zakodowany w Latin-1

gdy ten wyjątek występuje podczas próby załadowania zestawu danych, spróbuj użyć tego formatu

df=pd.read_csv("top50.csv",encoding='ISO-8859-1')

Dodaj technikę kodowania na końcu składni, która następnie akceptuje ładowanie zestawu danych.

surya
źródło
Cześć i witamy w SO! Proszę edytować swoje odpowiedzi, aby zapewnić, że poprawia po innych odpowiedzi już obecnych w tej kwestii.
hongsy
4

Użyj tego, jeśli pokazuje błąd UTF-8

pd.read_csv('File_name.csv',encoding='latin-1')
Anshul Singh Suryan
źródło
-1

W tym przypadku próbowałem uruchomić plik .py, który aktywował ścieżkę / plik.sql.

Moim rozwiązaniem było zmodyfikowanie kodyfikacji pliku.sql na „UTF-8 bez BOM” i działa!

Możesz to zrobić za pomocą Notepad ++.

zostawię część mojego kodu.

/ Kod /

con = psycopg2.connect (host = sys.argv [1], port = sys.argv [2], dbname = sys.argv [3], user = sys.argv [4], password = sys.argv [5]) )

kursor = con.cursor () sqlfile = open (ścieżka, 'r')

Martin Taco
źródło