web-dev-qa-db-fra.com

Comment corriger: "UnicodeDecodeError: le codec 'ascii' ne peut pas décoder octet"

as3:~/ngokevin-site# nano content/blog/20140114_test-chinese.mkd
as3:~/ngokevin-site# wok
Traceback (most recent call last):
File "/usr/local/bin/wok", line 4, in
Engine()
File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 104, in init
self.load_pages()
File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 238, in load_pages
p = Page.from_file(os.path.join(root, f), self.options, self, renderer)
File "/usr/local/lib/python2.7/site-packages/wok/page.py", line 111, in from_file
page.meta['content'] = page.renderer.render(page.original)
File "/usr/local/lib/python2.7/site-packages/wok/renderers.py", line 46, in render
return markdown(plain, Markdown.plugins)
File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 419, in markdown
return md.convert(text)
File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 281, in convert
source = unicode(source)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 1: ordinal not in range(128). -- Note: Markdown only accepts unicode input!

Comment le réparer?

Dans certaines autres applications de blog statiques basées sur python, la publication en chinois peut être publiée avec succès . Comme cette application: http://github.com/vrypan/bucket3 . Sur mon site http://bc3.brite.biz/ , la publication en chinois peut être publiée avec succès.

350
fisherman

Je l'ai finalement eu:

as3:/usr/local/lib/python2.7/site-packages# cat sitecustomize.py
# encoding=utf8  
import sys  

reload(sys)  
sys.setdefaultencoding('utf8')

Laisse moi vérifier:

as3:~/ngokevin-site# python
Python 2.7.6 (default, Dec  6 2013, 14:49:02)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> reload(sys)
<module 'sys' (built-in)>
>>> sys.getdefaultencoding()
'utf8'
>>>

Ce qui précède montre que l'encodage par défaut de python est utf8. Alors l'erreur n'est plus.

473
fisherman

Ne pas utiliser la réponse populaire (sys.setdefaultencoding('utf8'))

C'est un méchant hack (il y a une raison pour laquelle vous devez utiliser reload) qui ne fait que masquer les problèmes et gêner votre migration vers Python 3.x. Comprenez le problème, corrigez la cause première et profitez de zen Unicode ... Voir Pourquoi ne devrions-nous pas utiliser sys.setdefaultencoding ("utf-8") dans un script py? pour plus de détails

tl; dr/quick fix

  • Ne pas décoder/encoder bon gré mal gré
  • Ne présumez pas que vos chaînes sont encodées en UTF-8
  • Essayez de convertir les chaînes en chaînes Unicode dès que possible dans votre code.

Unicode Zen en Python 2.x - La version longue

Sans voir la source, il est difficile de connaître la cause du problème, il faudra donc que je parle de manière générale.

UnicodeDecodeError: 'ascii' codec can't decode byte se produit généralement lorsque vous essayez de convertir une str Python 2.x contenant des chaînes non-ASCII en chaîne Unicode sans spécifier le codage de la chaîne d'origine.

En bref, les chaînes Unicode sont un type de chaîne Python entièrement séparé qui ne contient aucun encodage. Ils ne contiennent que des codes Unicode point et peuvent donc contenir n'importe quel point Unicode de tout le spectre. Les chaînes contiennent du texte codé, beit UTF-8, UTF-16, ISO-8895-1, GBK, Big5, etc. Les chaînes sont décodées en Unicode et Unicodes sont codés en chaînes. Les fichiers et les données de texte sont toujours transférés dans des chaînes codées.

Les auteurs du module Markdown utilisent probablement unicode() (où l'exception est levée) comme porte de qualité vers le reste du code. Il convertit ASCII ou ré-encapsule les chaînes Unicodes existantes dans une nouvelle chaîne Unicode. Les auteurs de Markdown ne peuvent pas connaître l'encodage de la chaîne entrante et vous demanderont donc de décoder des chaînes en chaînes Unicode avant de les transmettre à Markdown.

Les chaînes Unicode peuvent être déclarées dans votre code à l'aide du préfixe u des chaînes. Par exemple.

>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>

Les chaînes Unicode peuvent également provenir de fichiers, de bases de données et de modules réseau. Lorsque cela se produit, vous n'avez pas à vous soucier de l'encodage.

Gotchas

La conversion de str en Unicode peut avoir lieu même si vous n'appelez pas explicitement unicode().

Les scénarios suivants entraînent des exceptions UnicodeDecodeError:

# Explicit conversion without encoding
unicode('€')

# New style format string into Unicode string
# Python will try to convert value string to Unicode first
u"The currency is: {}".format('€')

# Old style format string into Unicode string
# Python will try to convert value string to Unicode first
u'The currency is: %s' % '€'

# Append string to Unicode
# Python will try to convert string to Unicode first
u'The currency is: ' + '€'         

Exemples

Dans le diagramme suivant, vous pouvez voir comment Word café a été codé au format "UTF-8" ou "Cp1252" en fonction du type de terminal. Dans les deux exemples, caf est simplement un ascii régulier. En UTF-8, é est codé sur deux octets. Dans "Cp1252", é est 0xE9 (ce qui est également la valeur du point Unicode (ce n'est pas une coïncidence)). Le nom_fonction __ correct est appelé et la conversion en un code Unicode Python est réussie:  Diagram of a string being converted to a Python Unicode string

Dans ce diagramme, decode() est appelé avec ascii (ce qui revient à appeler decode() sans codage fourni). Comme ASCII ne peut pas contenir plus d'octets que 0x7F, une exception UnicodeDecodeError sera émise:

 Diagram of a string being converted to a Python Unicode string with the wrong encoding

Le sandwich Unicode

C'est une bonne pratique de former un sandwich Unicode dans votre code, où vous décodez toutes les données entrantes en chaînes Unicode, travaillez avec Unicodes, puis encodez en strs à la sortie. Cela vous évite de vous soucier de l'encodage des chaînes au milieu de votre code.

Entrée/décodage

Code source

Si vous devez intégrer du code non-ASCII dans votre code source, créez simplement des chaînes Unicode en préfixant celle-ci avec un u. Par exemple.

u'Zürich'

Pour permettre à Python de décoder votre code source, vous devrez ajouter un en-tête de codage correspondant au codage réel de votre fichier. Par exemple, si votre fichier a été codé en tant que 'UTF-8', vous utiliserez:

# encoding: utf-8

Cela n’est nécessaire que si vous avez non-ASCII dans votre code source .

Des dossiers

Habituellement, les données non-ASCII sont reçues d'un fichier. Le module io fournit un TextWrapper qui décode votre fichier à la volée, en utilisant une encoding donnée. Vous devez utiliser le bon encodage pour le fichier - il est difficile à deviner. Par exemple, pour un fichier UTF-8:

import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
     my_unicode_string = my_file.read() 

my_unicode_string conviendrait alors pour passer à Markdown. Si une UnicodeDecodeError de la ligne unicode(), vous avez probablement utilisé une valeur de codage incorrecte.

Fichiers CSV

Le module CSV Python 2.7 ne prend pas en charge les caractères non-ASCII ????. De l’aide est cependant disponible avec https://pypi.python.org/pypi/backports.csv .

Utilisez-le comme ci-dessus mais passez le fichier ouvert à celui-ci:

from backports import csv
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
    for row in csv.reader(my_file):
        yield row

Bases de données

La plupart des pilotes de base de données Python peuvent renvoyer des données au format Unicode, mais nécessitent généralement une petite configuration. Utilisez toujours des chaînes Unicode pour les requêtes SQL.

Dans la chaîne de connexion, ajoutez:

charset='utf8',
use_unicode=True

Par exemple.

>>> db = MySQLdb.connect(Host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")

Ajouter:

psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)

HTTP

Les pages Web peuvent être encodées dans n'importe quel encodage. L'en-tête Content-type doit contenir un champ charset pour indiquer le codage. Le contenu peut ensuite être décodé manuellement contre cette valeur. Alternativement, Python-Requests retourne les Unicodes dans response.text.Manuellement.

Si vous devez décoder les chaînes manuellement, vous pouvez simplement procéder à read(), où encoding est le codage approprié. Les codecs supportés par Python 2.x sont donnés ici: Encodages standard . Encore une fois, si vous obtenez UnicodeDecodeError, alors vous aurez probablement le mauvais encodage.

La viande du sandwich.

Travaillez avec Unicodes comme vous le feriez avec des chaînes normales.

Sortie.

Stdout/impression

print écrit dans le flux stdout. Python essaie de configurer un encodeur sur stdout afin que les Unicodes soient encodés dans l'encodage de la console. Par exemple, si la variable locale du shell Linux est en_GB.UTF-8, la sortie sera codée en UTF-8. Sous Windows, vous serez limité à une page de code 8 bits.

Une console configurée de manière incorrecte, telle que des paramètres régionaux corrompus, peut entraîner des erreurs d'impression inattendues. La variable d'environnement PYTHONIOENCODING peut forcer le codage pour stdout.

Des dossiers 

Comme pour les entrées, io.open peut être utilisé pour convertir de manière transparente des Unicodes en chaînes d'octets codées.

Base de données.

La même configuration pour la lecture permettra d’écrire directement les Unicodes.

Python 3.

Python 3 n'est plus compatible Unicode comme Python 2.x, mais la variable normale str est maintenant une chaîne Unicode et l'ancienne str est maintenant bytes.

Le codage par défaut est maintenant UTF-8. Par conséquent, si vous _my_string.decode(encoding) une chaîne d'octets sans indiquer de codage, Python 3 utilise le codage UTF-8. Cela corrige probablement 50% des problèmes Unicode des personnes. 

De plus, .decode() fonctionne en mode texte par défaut et renvoie donc __diffusé __ décodé __ (Unicode). Le codage est dérivé de vos paramètres régionaux, qui ont tendance à être UTF-8 sur les systèmes Un * x ou une page de code 8 bits, telle que Windows-1251, sur des fenêtres Windows.

Further, open() operates in text mode by default, so returns decoded str (Unicode ones). The encoding is derived from your locale, which tends to be UTF-8 on Un*x systems or an 8-bit code page, such as windows-1251, on Windows boxes.

439
Alastair McCormack

C’est le classique "problème unicode". Je pense qu'expliquer cela dépasse le cadre d'une réponse StackOverflow pour expliquer complètement ce qui se passe. 

C'est bien expliqué ici .

En résumé, vous avez passé quelque chose qui est interprété comme une chaîne d'octets à quelque chose qui doit le décoder en caractères Unicode, mais le codec par défaut (ascii) échoue.

La présentation que je vous ai indiquée fournit des conseils pour éviter cela. Faites de votre code un "sandwich unicode". En Python 2, l'utilisation de "from __future__ import unicode_literals" aide.

Mise à jour: comment corriger le code:

OK - dans votre variable "source", vous avez quelques octets. Votre question ne dit pas clairement comment ils y sont entrés - peut-être les lisez-vous à partir d’un formulaire Web? Dans tous les cas, ils ne sont pas encodés avec ascii, mais python tente de les convertir en unicode en supposant qu'ils le soient. Vous devez lui indiquer explicitement ce qu'est l'encodage. Cela signifie que vous devez savoir ce qu'est l'encodage! Ce n’est pas toujours facile et tout dépend de la provenance de cette chaîne. Vous pouvez expérimenter avec certains codages courants, par exemple UTF-8. Vous indiquez le codage à unicode () comme second paramètre:

source = unicode(source, 'utf-8')
119
GreenAsJade

Dans certains cas, lorsque vous vérifiez votre codage par défaut (print sys.getdefaultencoding()), il indique que vous utilisez ASCII. Si vous changez pour UTF-8, cela ne fonctionnera pas, cela dépend du contenu de votre variable . 

import sys
reload(sys)  
sys.setdefaultencoding('Cp1252')
38
Davy
"UnicodeDecodeError: 'ascii' codec can't decode byte"

Cause de cette erreur: chaîne_entrée doit être unicode mais str a été donné

"TypeError: Decoding Unicode is not supported"

Cause de cette erreur: tentative de convertir unicode input_string en unicode


Donc, vérifiez d’abord que votre chaîne input_string est str et convertissez-le en unicode si nécessaire:

if isinstance(input_string, str):
   input_string = unicode(input_string, 'utf-8')

Deuxièmement, ce qui précède modifie simplement le type mais ne supprime pas les caractères non ascii. Si vous souhaitez supprimer des caractères non-ASCII:

if isinstance(input_string, str):
   input_string = input_string.decode('ascii', 'ignore').encode('ascii') #note: this removes the character and encodes back to string.

Elif isinstance(input_string, unicode):
   input_string = input_string.encode('ascii', 'ignore')
17

Je cherchais à résoudre le message d'erreur suivant:

unicodedecodeerror: le codec 'ascii' ne peut pas décoder l'octet 0xe2 en position 5454: l'ordinal n'est pas dans la plage (128)

Je l'ai finalement résolu en spécifiant 'encoding':

f = open('../glove/glove.6B.100d.txt', encoding="utf-8")

Je souhaite que cela puisse vous aider aussi.

15
Zoe L

Je trouve que le mieux est de toujours convertir en unicode, mais c'est difficile à réaliser, car dans la pratique, il faudrait vérifier et convertir tous les arguments en fonctions et méthodes que vous avez écrites, y compris une forme de traitement de chaîne.

J'ai donc proposé l'approche suivante pour garantir des chaînes de caractères unicodes ou octets, quelle que soit l'entrée. En bref, inclut et utilise les lambdas suivants:

# guarantee unicode string
_u = lambda t: t.decode('UTF-8', 'replace') if isinstance(t, str) else t
_uu = lambda *tt: Tuple(_u(t) for t in tt) 
# guarantee byte string in UTF8 encoding
_u8 = lambda t: t.encode('UTF-8', 'replace') if isinstance(t, unicode) else t
_uu8 = lambda *tt: Tuple(_u8(t) for t in tt)

Exemples:

text='Some string with codes > 127, like Zürich'
utext=u'Some string with codes > 127, like Zürich'
print "==> with _u, _uu"
print _u(text), type(_u(text))
print _u(utext), type(_u(utext))
print _uu(text, utext), type(_uu(text, utext))
print "==> with u8, uu8"
print _u8(text), type(_u8(text))
print _u8(utext), type(_u8(utext))
print _uu8(text, utext), type(_uu8(text, utext))
# with % formatting, always use _u() and _uu()
print "Some unknown input %s" % _u(text)
print "Multiple inputs %s, %s" % _uu(text, text)
# but with string.format be sure to always work with unicode strings
print u"Also works with formats: {}".format(_u(text))
print u"Also works with formats: {},{}".format(*_uu(text, text))
# ... or use _u8 and _uu8, because string.format expects byte strings
print "Also works with formats: {}".format(_u8(text))
print "Also works with formats: {},{}".format(*_uu8(text, text))

Voici un peu plus raisonnement à ce sujet .

8
miraculixx

Encode convertit un objet unicode en un objet chaîne. Je pense que vous essayez d'encoder un objet string. convertissez d'abord votre résultat en objet unicode, puis encodez-le en 'utf-8' ..__

    result = yourFunction()
    result.decode().encode('utf-8')
5
RAFI AFRIDI

J'ai eu le même problème mais cela n'a pas fonctionné pour Python 3. Je l'ai suivi et cela a résolu mon problème:

enc = sys.getdefaultencoding()
file = open(menu, "r", encoding = enc)

Vous devez définir le codage lorsque vous lisez/écrivez le fichier.

3
Reihan_amn

En bref, pour assurer une gestion correcte de l’unicode dans Python 2:

  • utiliser io.open pour lire/écrire des fichiers
  • utiliser from __future__ import unicode_literals
  • configurer d'autres entrées/sorties de données (bases de données, réseau, par exemple) pour utiliser unicode
  • si vous ne pouvez pas configurer les sorties en utf-8, convertissez votre sortie pour elles print(text.encode('ascii', 'replace').decode())

Pour des explications, voir @Alastair McCormack réponse détaillée .

2
idbrii

J'ai eu le même problème avec la chaîne "Pastelería Mallorca" et j'ai résolu avec:

unicode("Pastelería Mallorca", 'latin-1')
2
Alle Pavesi

Cette erreur se produit lorsque notre chaîne contient des caractères autres que des caractères ASCII et que nous effectuons des opérations sur cette chaîne sans décodage correct . colonnes ID, texte et décodage des caractères comme ci-dessous:

train_df = pd.read_csv("Example.csv")
train_data = train_df.values
for i in train_data:
    print("ID :" + i[0])
    text = i[1].decode("utf-8",errors="ignore").strip().lower()
    print("Text: " + text)
1
Sravya

Dans un projet Django (1.9.10)/Python 2.7.5, j'ai des exceptions UnicodeDecodeError fréquentes; principalement lorsque j'essaie d'alimenter des chaînes de caractères unicode. J'ai créé une fonction d'assistance pour les objets arbitraires afin de formater les chaînes ascii 8 bits et de remplacer tous les caractères qui ne figurent pas dans la table par "?". Je pense que ce n'est pas la meilleure solution, mais puisque l'encodage par défaut est ascii (et je ne veux pas le changer), il conviendra:

 def encode_for_logging (c, encoding = 'ascii'): 
 si estinstance (c, basestring): 
 retourne c.encode (encodage, 'remplacer') 
 Elif isinstance (c, Iterable): 
 c_ = [] 
 pour v dans c: 
 c_.append (encode_for_logging (v, encodage)) 
 retourne c _
 autre:
 renvoyer encode_for_logging (unicode (c)) 
`

1
Paul Bormans

J'ai eu la même erreur, avec des URL contenant des caractères non-ASCII (octets avec des valeurs> 128)

url = url.decode('utf8').encode('utf-8')

Remarque: utf-8, utf8 sont simplement des alias. Utiliser uniquement 'utf8' ou 'utf-8' devrait fonctionner de la même manière

Dans mon cas, travaillant pour moi, en Python 2.7, je suppose que cette assignation a changé 'quelque chose' dans la représentation interne str - c’est-à-dire qu’elle force le décodage correct de la séquence d’octets sauvegardée dans url et place finalement la chaîne dans un utf-8 str avec toute la magie au bon endroit . Unicode en Python est une magie noire pour moi . J'espère utile

1
Fabiano Tarlao

Vous avez une même erreur et cela a résolu mon erreur. Merci! Python 2 et Python 3 ayant une gestion unicode différente, les fichiers picklés sont tout à fait incompatibles à charger. Utilisez donc l’argument d’encodage de Python Pickle. Le lien ci-dessous m'a aidé à résoudre le problème similaire lorsque j'essayais d'ouvrir des données picklées à partir de mon python 3.7, alors que mon fichier était enregistré à l'origine dans la version 2.x de python. https://blog.modest-destiny.com/posts/python-2-and-3-compatible-pickle-save-and-load/ Je copie la fonction load_pickle dans mon script et appelle le load_pickle (pickle_file ) en chargeant mon input_data comme ceci:

input_data = load_pickle("my_dataset.pkl")

La fonction load_pickle est ici:

def load_pickle(pickle_file):
    try:
        with open(pickle_file, 'rb') as f:
            pickle_data = pickle.load(f)
    except UnicodeDecodeError as e:
        with open(pickle_file, 'rb') as f:
            pickle_data = pickle.load(f, encoding='latin1')
    except Exception as e:
        print('Unable to load data ', pickle_file, ':', e)
        raise
    return pickle_data
0
Ganesh Shah

Cela a fonctionné pour moi:

    file = open('docs/my_messy_doc.pdf', 'rb')
0
saran3h

Spécifiez: # encoding = utf-8 en haut de votre fichier Python, cela devrait résoudre le problème.

0
Sameer Choudhary

Afin de résoudre ce problème au niveau du système d'exploitation dans une installation Ubuntu, vérifiez les points suivants:

$ locale charmap

Si vous obtenez

locale: Cannot set LC_CTYPE to default locale: No such file or directory

au lieu de

UTF-8

puis définissez LC_CTYPE et LC_ALL comme ceci:

$ export LC_ALL="en_US.UTF-8"
$ export LC_CTYPE="en_US.UTF-8"
0
vervas