UnicodeDecodeError: le codec 'utf8' ne peut pas décoder l'octet 0x9c


289

J'ai un serveur de socket qui est censé recevoir des caractères valides UTF-8 des clients.

Le problème est que certains clients (principalement des pirates informatiques) envoient tous les mauvais types de données dessus.

Je peux facilement distinguer le client authentique, mais je me connecte aux fichiers de toutes les données envoyées afin de pouvoir les analyser plus tard.

Parfois, je reçois des caractères comme celui-ci œqui provoquent l' UnicodeDecodeErrorerreur.

J'ai besoin de pouvoir faire la chaîne UTF-8 avec ou sans ces caractères.


Mettre à jour:

Pour mon cas particulier, le service de socket était un MTA et je m'attends donc à recevoir des commandes ASCII telles que:

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

J'enregistrais tout cela dans JSON.

Ensuite, des gens sans bonnes intentions ont décidé de vendre toutes sortes de déchets.

C'est pourquoi pour mon cas spécifique, il est parfaitement correct de supprimer les caractères non ASCII.


1
la chaîne sort-elle d'un fichier ou d'une socket? pourriez-vous s'il vous plaît publier des exemples de code de la façon dont la chaîne est encodée et décodée avant d'être envoyée via le socket / gestionnaire de fichiers?
devsnd

Ai-je écrit ou non que la chaîne arrive sur le socket? Je lis simplement la chaîne depuis le socket et avec pour la mettre dans un dictionnaire, puis je la JSON pour l'envoyer. La fonction JSON a échoué en raison de ces caractères.
transilvlad

pouvez-vous s'il vous plaît mettre vos exemples de données de problème
Shubham Sharma

Réponses:


343

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

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

ou

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

Remarque: Cela supprimera (ignorera) les caractères en question en renvoyant la chaîne sans eux.

Pour moi, c'est le cas idéal car je l'utilise comme protection contre les entrées non ASCII qui ne sont pas autorisées par mon application.

Alternativement: Utilisez la méthode ouverte du codecsmodule pour lire le fichier:

import codecs
with codecs.open(file_name, 'r', encoding='utf-8',
                 errors='ignore') as fdata:

45
Oui, bien que ce soit généralement une mauvaise pratique / dangereuse, car vous perdrez simplement des personnages. Mieux vaut déterminer ou détecter l'encodage de la chaîne d'entrée et le décoder en unicode d'abord, puis encoder en UTF-8, par exemple:str.decode('cp1252').encode('utf-8')
Ben Hoyt

Dans certains cas, oui, vous avez raison, cela peut causer des problèmes. Dans mon cas, je m'en fiche car ils semblent être des caractères supplémentaires provenant d'un mauvais formatage et d'une mauvaise programmation des clients se connectant à mon serveur de socket.
transilvlad

Celui-ci aide réellement si le contenu de la chaîne n'est pas valide, dans mon cas, '\xc0msterdam'qui se transforme en u'\ufffdmsterdam'remplacement
PvdL

3
si vous vous êtes retrouvé ici parce que vous rencontrez des problèmes pour lire un fichier, ouvrir le fichier en mode binaire pourrait aider: open(file_name, "rb")puis appliquer l'approche de Ben à partir des commentaires ci
kristian

la même option s'applique à encore plus, par exemple à "something.decode ()"
Alexander Stohr

83

Changer le moteur de C en Python a fait l'affaire pour moi.

Le moteur est C:

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

Le codec 'utf-8' ne peut pas décoder l'octet 0x92 en position 18: octet de début invalide

Le moteur est Python:

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

Aucune erreur pour moi.


3
c'est en fait une bonne solution. je ne sais pas pourquoi il a été rejeté.
ℕʘʘḆḽḘ

Cela pourrait ne pas être une bonne idée si vous avez un gros csvfichier. Cela pourrait vous conduire à une OutOfMemoryerreur ou à un redémarrage automatique du noyau de votre ordinateur portable. Vous devez définir le encodingsur ce cas.
LucasBr

1
Excellente réponse. Merci. Cela a fonctionné pour moi. J'avais "?" À l'intérieur d'un caractère en forme de diamant qui causait le problème. Avec des yeux simples, j'avais "" "qui est en pouces. J'ai fait 2 choses pour comprendre. a) df = pd.read_csv ('test.csv', n_rows = 10000). Cela fonctionnait parfaitement sans le moteur. J'ai donc incrémenté les n_rows pour déterminer quelle ligne avait une erreur. b) df = pd.read_csv ('test.csv', engine = 'python'). Cela a fonctionné et j'ai imprimé la ligne erronée en utilisant df.iloc [36145], cela m'a imprimé l'enregistrement erroné.
Jagannath Banerjee

1
cela a fonctionné pour moi aussi ... Je ne sais pas ce qui se passe `` sous le capot '' et si c'est en fait une bonne / bonne / bonne solution dans tous les cas, mais cela a fait l'affaire pour moi;)
Chrisvdberge

1
Excellente solution! Merci beaucoup.
Pechi

62

Ce type de problème apparaît pour moi maintenant que je suis passé à Python 3. Je ne savais pas que Python 2 roulait simplement à la vapeur tout problème avec l'encodage de fichiers.

J'ai trouvé cette belle explication des différences et comment trouver une solution après qu'aucune des solutions ci-dessus n'ait fonctionné pour moi.

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

En bref, pour que Python 3 se comporte de manière aussi similaire que possible à Python 2, utilisez:

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

Cependant, lisez l'article, il n'y a pas de solution unique.


29
>>> '\x9c'.decode('cp1252')
u'\u0153'
>>> print '\x9c'.decode('cp1252')
œ

16
Je suis confus, comment avez-vous choisi cp1252? Cela a fonctionné pour moi, mais pourquoi? Je ne sais pas et maintenant je suis perdu: /. Pourriez-vous élaborer? Merci beaucoup ! :)
Cyril N.

4
Pourriez-vous présenter une option qui fonctionne pour tous les personnages? Existe-t-il un moyen de détecter les caractères qui doivent être décodés afin qu'un code plus générique puisse être implémenté? Je vois que beaucoup de gens regardent cela et je parie que certains rejets ne sont pas l'option souhaitée comme c'est le cas pour moi.
transilvlad

Comme vous pouvez le voir, cette question a une grande popularité. Vous pensez pouvoir étendre votre réponse avec une solution plus générique?
transilvlad

13
Il n'y a pas de solution plus générique pour "Devinez la roulette d'encodage"
Puppy

5
trouvé en utilisant une combinaison de recherche sur le Web, de chance et d'intuition: cp1252 wasused by default in the legacy components of Microsoft Windows in English and some other Western languages
bolov

24

J'ai eu le même problème avec UnicodeDecodeErroret je l'ai résolu avec cette ligne. Je ne sais pas si c'est la meilleure façon mais cela a fonctionné pour moi.

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

13

le premier, Utilisation de get_encoding_type pour obtenir le type de codage des fichiers:

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

la seconde, en ouvrant les fichiers avec le type:

open(current_file, 'r', encoding = get_encoding_type, errors='ignore')

1
ce qui se passe quand il revient Aucun
Chop Labalagun

3

Juste au cas où quelqu'un aurait le même problème. J'utilise vim avec YouCompleteMe , je n'ai pas pu démarrer ycmd avec ce message d'erreur, ce que j'ai fait est:export LC_CTYPE="en_US.UTF-8" le problème a disparu.


2
Quel est le rapport avec cette question?
transilvlad

1
Exactement la même chose, si vous savez comment fonctionne votre système. Le plugin Ycm est une architecture de socket, la communication entre le client et le serveur utilise un socket, les deux sont des modules python, pas en mesure de décoder les paquets si le paramètre de codage est incorrect
workplaylifecycle

J'ai le même problème. Pouvez-vous me dire où mettre export LC_CTYPE="en_US.UTF-8"?
Reman

@Remonn salut, vous savez que nous avons un fichier de profil pour bash? Mettre dedans.
workplaylifecycle

@hylepo, je suis sur un système Windows :)
Reman

3

Que pouvez-vous faire si vous devez modifier un fichier, mais que vous ne connaissez pas l'encodage du fichier? Si vous savez que l'encodage est compatible ASCII et que vous souhaitez uniquement examiner ou modifier les parties ASCII, vous pouvez ouvrir le fichier avec le gestionnaire d'erreurs de substitution:

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

0

J'ai résolu ce problème simplement en ajoutant

df = pd.read_csv(fileName,encoding='latin1')
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.