UnicodeDecodeError, octet de continuation invalide

257

Pourquoi l'élément ci-dessous échoue? et pourquoi réussit-il avec le codec "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")

résulte en:

 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
la source

Réponses:

247

En binaire, 0xE9 ressemble 1110 1001. Si vous lisez sur UTF-8 sur Wikipedia , vous verrez qu'un tel octet doit être suivi de deux du formulaire 10xx xxxx. Ainsi, par exemple:

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

Mais ce n'est que la cause mécanique de l'exception. Dans ce cas, vous avez une chaîne qui est presque certainement encodée en latin 1. Vous pouvez voir comment UTF-8 et latin 1 sont différents:

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

(Remarque, j'utilise ici un mélange de représentations Python 2 et 3. L'entrée est valide dans n'importe quelle version de Python, mais il est peu probable que votre interprète Python affiche à la fois les chaînes unicode et les chaînes d'octets de cette manière.)

Josh Lee
la source
2
Merci (et à l'autre qui a répondu), je croyais à tort que les caractères jusqu'à 255 se convertiraient directement.
RuiDC
Je reçois une UnicodeEncodeError: 'ascii' codec can't encode characters in position 2-3: ordinal not in range(128)erreur lors de l'utilisation.encode(latin-1)
Shiva
234

J'ai eu la même erreur lorsque j'ai essayé d'ouvrir un fichier csv par la méthode read_csv de pandas.

La solution a été de changer l'encodage en «latin-1»:

pd.read_csv('ml-100k/u.item', sep='|', names=m_cols , encoding='latin-1')
Mazen Aly
la source
1
Est-ce que cela résout le problème? Ne dit-il pas simplement aux pandas d'ignorer l'octet en rétrogradant vers un style d'encodage moins complexe?
Yu Chen
61

Il n'est pas valide UTF-8. Ce caractère est le caractère e-aigu dans ISO-Latin1, c'est pourquoi il réussit avec ce jeu de codes.

Si vous ne connaissez pas le jeu de codes dans lequel vous recevez des chaînes, vous avez un peu de mal. Il serait préférable qu'un seul jeu de codes (espérons-le UTF-8) soit choisi pour votre protocole / application, puis vous rejetteriez simplement ceux qui n'ont pas été décodés.

Si vous ne pouvez pas faire cela, vous aurez besoin d'heuristiques.

Sami J. Lehtinen
la source
2
Et pour l'heuristique, voir la bibliothèque chardet.
mlissner
44

Parce que UTF-8 est multi-octets et qu'il n'y a pas de caractère correspondant à votre combinaison de \xe9 espace plus suivant.

Pourquoi devrait-il réussir à la fois en utf-8 et en latin-1?

Voici comment la même phrase devrait être dans utf-8:

>>> o.decode('latin-1').encode("utf-8")
'a test of \xc3\xa9 char'
neurino
la source
Latin-1 est une famille de codage à un octet, donc tout ce qu'il contient doit être défini en UTF-8. Mais pourquoi parfois Latin-1 gagne-t-il?
Reihan_amn
11

Si cette erreur survient lors de la manipulation d'un fichier qui vient d'être ouvert, vérifiez si vous l'avez ouvert en 'rb'mode

Patrick Mutuku
la source
2
Grâce à cette réponse, a pu éviter l'erreur de UnicodeDecodeError: le codec 'utf-8' ne peut pas décoder l'octet 0xd7 en position 2024079: octet de continuation invalide par soup = BeautifulSoup(open('webpage.html', 'rb'), 'html.parser')
Isaac Philip
6

Cela m'est arrivé aussi, alors que je lisais du texte contenant l'hébreu d'un .txt fichier.

J'ai cliqué: file -> save aset j'ai enregistré ce fichier en tant UTF-8qu'encodage

Alon Gouldman
la source
5

L'erreur de code utf-8 survient généralement lorsque la plage de valeurs numériques dépasse 0 à 127.

la raison de lever cette exception est:

1) Si le point de code est <128, chaque octet est identique à la valeur du point de code. 2) Si le point de code est 128 ou supérieur, la chaîne Unicode ne peut pas être représentée dans cet encodage. (Python déclenche une exception UnicodeEncodeError dans ce cas.)

Afin de surmonter cela, nous avons un ensemble d'encodages, le plus largement utilisé est "Latin-1, également connu sous le nom ISO-8859-1"

Ainsi, les points Unicode ISO-8859-1 0–255 sont identiques aux valeurs Latin-1, donc la conversion vers ce codage nécessite simplement de convertir les points de code en valeurs d'octets; si un point de code supérieur à 255 est rencontré, la chaîne ne peut pas être codée en latin-1

lorsque cette exception se produit lorsque vous essayez de charger un ensemble de données, essayez d'utiliser ce format

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

Ajoutez une technique d'encodage à la fin de la syntaxe qui accepte ensuite de charger l'ensemble de données.

surya
la source
Salut et bienvenue à SO! Veuillez modifier votre réponse pour vous assurer qu'elle améliore les autres réponses déjà présentes dans cette question.
Hongsy
4

Utilisez ceci, s'il montre l'erreur d'UTF-8

pd.read_csv('File_name.csv',encoding='latin-1')
Anshul Singh Suryan
la source
-1

Dans ce cas, j'ai essayé d'exécuter un .py qui active un chemin / fichier.sql.

Ma solution a été de modifier la codification du fichier.sql en "UTF-8 sans BOM" et ça marche!

Vous pouvez le faire avec Notepad ++.

je vais laisser une partie de mon code.

/ Code /

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

cursor = con.cursor () sqlfile = open (chemin, 'r')

Martin Taco
la source