web-dev-qa-db-fra.com

UnicodeEncodeError: le codec 'ascii' ne peut pas coder le caractère u '\ xa0' en position 20: l'ordinal n'est pas dans la plage (128)

J'ai des problèmes à gérer les caractères Unicode à partir de texte extrait de différentes pages Web (sur différents sites). J'utilise BeautifulSoup.

Le problème est que l'erreur n'est pas toujours reproductible. cela fonctionne parfois avec certaines pages, et parfois, cela se fait en jetant un UnicodeEncodeError. J'ai essayé à peu près tout ce à quoi je peux penser, et pourtant je n'ai rien trouvé qui fonctionne de manière cohérente sans générer une sorte d'erreur liée à Unicode.

L'une des sections de code à l'origine des problèmes est illustrée ci-dessous:

agent_telno = agent.find('div', 'agent_contact_number')
agent_telno = '' if agent_telno is None else agent_telno.contents[0]
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()

Voici une trace de pile générée sur QUELQUES chaînes lorsque le fragment de code ci-dessus est exécuté:

Traceback (most recent call last):
  File "foobar.py", line 792, in <module>
    p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 20: ordinal not in range(128)

Je suppose que cela est dû au fait que certaines pages (ou plus spécifiquement, les pages de certains sites) peuvent être encodées, alors que d’autres peuvent ne pas être encodées. Tous les sites sont basés au Royaume-Uni et fournissent des données destinées à la consommation britannique. Il n'y a donc pas de problème d'internalisation ou de traitement de texte rédigé dans un langage autre que l'anglais.

Quelqu'un a-t-il des idées sur la façon de résoudre ce problème afin que je puisse résoudre ce problème de manière constante?

1183

Vous devez lire le Python nicode HOWTO . Cette erreur est le tout premier exemple .

Essentiellement, arrêtez d'utiliser str pour convertir unicode en texte/octets codés.

A la place, utilisez correctement .encode() pour coder la chaîne:

p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()

ou travaillez entièrement en unicode.

1266
agf

C'est un point de douleur classique python unicode! Considérer ce qui suit:

a = u'bats\u00E0'
print a
 => batsà

Tout va bien jusqu'à présent, mais si nous appelons str (a), voyons ce qui se passe:

str(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)

Oh dip, ça ne fera de bien à personne! Pour corriger l'erreur, encodez explicitement les octets avec .encode et indiquez à python le codec à utiliser:

a.encode('utf-8')
 => 'bats\xc3\xa0'
print a.encode('utf-8')
 => batsà

Voil\u00E0!

Le problème est que lorsque vous appelez str (), python utilise le codage de caractères par défaut pour essayer de coder les octets que vous lui avez attribués, qui dans votre cas sont parfois des représentations de caractères Unicode. Pour résoudre le problème, vous devez indiquer à python comment traiter la chaîne que vous lui attribuez à l'aide de .encode ('what_unicode'). La plupart du temps, vous devriez pouvoir utiliser utf-8.

Pour une excellente présentation sur ce sujet, voir la conférence PyCon de Ned Batchelder ici: http://nedbatchelder.com/text/unipain.html

417
Andbdrew

J'ai trouvé un travail élégant autour de moi pour supprimer des symboles et continuer à conserver chaîne sous forme de chaîne comme suit:

yourstring = yourstring.encode('ascii', 'ignore').decode('ascii')

Il est important de noter que l'utilisation de l'option ignore est dangereuse car elle supprime silencieusement toute prise en charge unicode (et internationalisation) du code qui l'utilise, comme indiqué ici (conversion unicode):

>>> u'City: Malmö'.encode('ascii', 'ignore').decode('ascii')
'City: Malm'
196
Max Korolevsky

eh bien, j'ai tout essayé mais cela n'a pas aidé, après avoir cherché sur Google, j'ai pensé ce qui suit et cela m'a aidé. python 2.7 est en cours d'utilisation.

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
140
Ashwin

Un problème subtil entraînant même l’échec de l’impression est le mauvais paramétrage de vos variables d’environnement, par exemple. ici LC_ALL mis à "C". Dans Debian, ils découragent de le définir: wiki de Debian sur un paramètre régional

$ echo $LANG
en_US.utf8
$ echo $LC_ALL 
C
$ python -c "print (u'voil\u00e0')"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)
$ export LC_ALL='en_US.utf8'
$ python -c "print (u'voil\u00e0')"
voilà
$ unset LC_ALL
$ python -c "print (u'voil\u00e0')"
voilà
80
maxpolk

Pour moi, ce qui a fonctionné a été:

BeautifulSoup(html_text,from_encoding="utf-8")

J'espère que ça aide quelqu'un.

27
Animesh

En fait, j'ai découvert que dans la plupart de mes cas, il est beaucoup plus simple de supprimer ces caractères:

s = mystring.decode('ascii', 'ignore')
24
Phil LaNasa

Essayez ceci pourrait résoudre,

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
20
Joseph Daudi

Le problème est que vous essayez d'imprimer un caractère Unicode, mais votre terminal ne le prend pas en charge.

Vous pouvez essayer d'installer le package _language-pack-en_ pour résoudre ce problème:

_Sudo apt-get install language-pack-en
_

qui fournit des mises à jour des données de traduction en anglais pour tous les packages pris en charge (y compris Python). Installez un package linguistique différent si nécessaire (en fonction des caractères que vous essayez d'imprimer).

Sur certaines distributions Linux, il est nécessaire de s’assurer que les paramètres régionaux anglais par défaut sont configurés correctement (pour que les caractères unicode puissent être gérés par Shell/terminal). Parfois, il est plus facile de l'installer que de le configurer manuellement.

Ensuite, lorsque vous écrivez le code, veillez à utiliser le bon codage dans votre code.

Par exemple:

_open(foo, encoding='utf-8')
_

Si le problème persiste, vérifiez bien la configuration de votre système, par exemple:

  • Votre fichier de paramètres régionaux (_/etc/default/locale_), qui devrait par ex.

    _LANG="en_US.UTF-8"
    LC_ALL="en_US.UTF-8"
    _

    ou:

    _LC_ALL=C.UTF-8
    LANG=C.UTF-8
    _
  • Valeur de LANG/ LC_CTYPE dans Shell.

  • Vérifiez les paramètres régionaux que votre shell prend en charge en:

    _locale -a | grep "UTF-8"
    _

Démonstration du problème et de la solution dans une nouvelle VM.

  1. Initialisez et configurez le VM (par exemple, à l'aide de vagrant ):

    _vagrant init ubuntu/trusty64; vagrant up; vagrant ssh
    _

    Voir: boîtes Ubuntu disponibles ..

  2. Impression de caractères Unicode (tels que des signes de marque tels que __):

    _$ python -c 'print(u"\u2122");'
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
    UnicodeEncodeError: 'ascii' codec can't encode character u'\u2122' in position 0: ordinal not in range(128)
    _
  3. Installation actuelle de _language-pack-en_:

    _$ Sudo apt-get -y install language-pack-en
    The following extra packages will be installed:
      language-pack-en-base
    Generating locales...
      en_GB.UTF-8... /usr/sbin/locale-gen: done
    Generation complete.
    _
  4. Maintenant, le problème devrait être résolu:

    _$ python -c 'print(u"\u2122");'
    ™
    _
  5. Sinon, essayez la commande suivante:

    _$ LC_ALL=C.UTF-8 python -c 'print(u"\u2122");'
    ™
    _
19
kenorb

Ajoutez la ligne ci-dessous au début de votre script (ou en deuxième ligne):

# -*- coding: utf-8 -*-

C'est la définition de python encodage du code source. Plus d'infos dans PEP 26 .

16
Andriy Ivaneyko

Voici un récapitulatif de quelques autres réponses dites "cop out". Il existe des situations dans lesquelles le simple fait de jeter les caractères/chaînes gênants est une bonne solution, malgré les protestations exprimées ici.

def safeStr(obj):
    try: return str(obj)
    except UnicodeEncodeError:
        return obj.encode('ascii', 'ignore').decode('ascii')
    except: return ""

Le tester:

if __== '__main__': 
    print safeStr( 1 ) 
    print safeStr( "test" ) 
    print u'98\xb0'
    print safeStr( u'98\xb0' )

Résultats:

1
test
98°
98

Suggestion: vous pouvez appeler cette fonction toAscii à la place? C'est une question de préférence.

Ceci a été écrit pour Python 2. Pour Python 3, je pense que vous voudrez utiliser bytes(obj,"ascii") plutôt que str(obj) . Je n'ai pas encore testé cela, mais je vais à un moment donné et réviser la réponse.

14
BuvinJ

En coquille:

  1. Recherchez les paramètres régionaux UTF-8 pris en charge à l'aide de la commande suivante:

    locale -a | grep "UTF-8"
    
  2. Exportez-le, avant d'exécuter le script, par exemple:

    export LC_ALL=$(locale -a | grep UTF-8)
    

    ou manuellement comme:

    export LC_ALL=C.UTF-8
    
  3. Testez-le en imprimant un caractère spécial, par exemple. :

    python -c 'print(u"\u2122");'
    

Ci-dessus testé dans Ubuntu.

11
kenorb

Je mets toujours le code ci-dessous dans les deux premières lignes des fichiers python:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
8
Pereira

Fonctions d'assistance simples trouvées ici .

def safe_unicode(obj, *args):
    """ return the unicode representation of obj """
    try:
        return unicode(obj, *args)
    except UnicodeDecodeError:
        # obj is byte string
        ascii_text = str(obj).encode('string_escape')
        return unicode(ascii_text)

def safe_str(obj):
    """ return the byte string representation of obj """
    try:
        return str(obj)
    except UnicodeEncodeError:
        # obj is unicode
        return unicode(obj).encode('unicode_escape')
6

Il suffit d'ajouter à une variable encode ('utf-8')

agent_contact.encode('utf-8')
5
Kairat Koibagarov

Cela aide dans python 2.7

import sys
reload(sys)   
sys.setdefaultencoding('utf-8')

Cela aide à réactiver sys.setdefaultencoding ()

5
Edward Okech

La solution ci-dessous a fonctionné pour moi, vient d’être ajoutée

u "String"

(représentant la chaîne en tant qu'unicode) avant ma chaîne.

result_html = result.to_html(col_space=1, index=False, justify={'right'})

text = u"""
<html>
<body>
<p>
Hello all, <br>
<br>
Here's weekly summary report.  Let me know if you have any questions. <br>
<br>
Data Summary <br>
<br>
<br>
{0}
</p>
<p>Thanks,</p>
<p>Data Team</p>
</body></html>
""".format(result_html)
3

Ouvrez le terminal et lancez la commande ci-dessous:

export LC_ALL="en_US.UTF-8"
3

Je viens d'utiliser ce qui suit:

import unicodedata
message = unicodedata.normalize("NFKD", message)

Vérifiez ce que dit la documentation à ce sujet:

unicodedata.normalize (form, unistr) Retourne la forme normale pour la chaîne Unicode unistr. Les valeurs valides pour la forme sont "NFC", "NFKC", "NFD" et "NFKD".

Le standard Unicode définit différentes formes de normalisation d'une chaîne Unicode, basées sur la définition de l'équivalence canonique et de l'équivalence de compatibilité. En Unicode, plusieurs caractères peuvent être exprimés de différentes manières. Par exemple, le caractère U + 00C7 (LETTRE MAJUSCULE LATINE C AVEC CEDILLA) peut également être exprimé par la séquence U + 0043 (LETTRE MAJUSCULE LATINE C) U + 0327 (COMBINAISON CEDILLA).

Pour chaque caractère, il existe deux formes normales: la forme normale C et la forme normale D. La forme normale D (NFD) est également appelée décomposition canonique et traduit chaque caractère dans sa forme décomposée. La forme normale C (NFC) applique d’abord une décomposition canonique, puis compose à nouveau des caractères pré-combinés.

En plus de ces deux formes, il existe deux formes normales supplémentaires basées sur l'équivalence de compatibilité. En Unicode, certains caractères sont pris en charge et devraient normalement être unifiés avec d’autres caractères. Par exemple, U + 2160 (ROMAN NUMERO ONE) est vraiment la même chose que U + 0049 (LETTRE MAJUSCULE LATINE I). Toutefois, la compatibilité avec les jeux de caractères existants est prise en charge dans Unicode (par exemple, gb2312).

La forme normale KD (NFKD) appliquera la décomposition de compatibilité, c'est-à-dire remplacera tous les caractères de compatibilité par leurs équivalents. La forme normale KC (NFKC) applique d'abord la décomposition de compatibilité, suivie de la composition canonique.

Même si deux chaînes unicode sont normalisées et ont le même aspect pour un lecteur humain, si l’un a des caractères combinés et l’autre pas, il se peut que leur comparaison ne soit pas égale.

Le résout pour moi. Simple et facile.

3
Drag0

Nous avons rencontré cette erreur lors de l'exécution de manage.py migrate dans Django avec des fixtures localisées.

Notre source contenait la déclaration # -*- coding: utf-8 -*-, MySQL était correctement configuré pour utf8 et Ubuntu disposait du paquet de langue et des valeurs appropriés dans /etc/default/locale.

Le problème était simplement que le conteneur Django (nous utilisons docker) manquait de la variable LANG env.

Définir LANG sur en_US.UTF-8 et redémarrer le conteneur avant de réexécuter les migrations a résolu le problème.

2
followben

Hélas, cela fonctionne dans Python 3 au moins ...

Python

Parfois, l’erreur se situe dans les variables d’environnement et s’enveloppe

import os
import locale
os.environ["PYTHONIOENCODING"] = "utf-8"
myLocale=locale.setlocale(category=locale.LC_ALL, locale="en_GB.UTF-8")
... 
print(myText.encode('utf-8', errors='ignore'))

où les erreurs sont ignorées dans l'encodage.

1
hhh

Je viens d'avoir ce problème, et Google m'a conduit ici, donc pour ajouter aux solutions générales, voici ce qui a fonctionné pour moi:

# 'value' contains the problematic data
unic = u''
unic += value
value = unic

J'ai eu cette idée après avoir lu présentation de Ned .

Je ne prétends pas comprendre parfaitement pourquoi cela fonctionne, cependant. Donc, si quelqu'un peut modifier cette réponse ou ajouter un commentaire pour l'expliquer, je l'apprécierai.

1
pepoluan

Beaucoup de réponses ici (@agf et @Andbdrew par exemple) ont déjà abordé les aspects les plus immédiats de la question du PO.

Cependant, je pense qu’il existe un aspect subtil mais important qui a été en grande partie ignoré et qui compte beaucoup pour tous ceux qui, comme moi, se sont retrouvés ici en essayant de donner un sens aux encodages en Python: Python 2 vs Python 3 la gestion de la représentation des caractères est très différente . Je me sens comme une grosse part de confusion à cause de la lecture de codages dans Python par des personnes qui ne connaissent pas la version.

Je suggère à toute personne intéressée de comprendre la cause fondamentale du problème OP de commencer par lire introduction de Spolsky aux représentations de caractères et Unicode, puis passer à Batchelder sous Unicode dans Python 2 et Python 3.

0

Essayez d'éviter la conversion de variable en str (variable). Parfois, cela peut causer le problème.

Astuce simple à éviter:

try: 
    data=str(data)
except:
    data = str(data)

L'exemple ci-dessus résoudra également Encode erro.

0
sam ruben

Si vous avez quelque chose comme packet_data = "This is data", faites-le à la ligne suivante, juste après l'initialisation de packet_data:

unic = u''
packet_data = unic
0
Nandan Kulkarni

Mise à jour pour python 3.0 et versions ultérieures. Essayez ce qui suit dans l’éditeur python:

locale-gen en_US.UTF-8
export LANG=en_US.UTF-8 LANGUAGE=en_US.en
LC_ALL=en_US.UTF-8

Ceci définit le codage des paramètres régionaux par défaut du système au format UTF-8.

Plus d'informations peuvent être lues ici PEP 538 - Coercition des paramètres régionaux C hérités vers des paramètres régionaux UTF-8 .

0
ZF007

J'ai eu ce problème en essayant de générer des caractères Unicode sur stdout, mais avec sys.stdout.write, plutôt que sur print (pour pouvoir également prendre en charge la sortie dans un fichier différent).

de la propre documentation de BeautifulSoup , j'ai résolu ceci avec la bibliothèque de codecs:

import sys
import codecs

def main(fIn, fOut):
    soup = BeautifulSoup(fIn)
    # Do processing, with data including non-ASCII characters
    fOut.write(unicode(soup))

if __== '__main__':
    with (sys.stdin) as fIn: # Don't think we need codecs.getreader here
        with codecs.getwriter('utf-8')(sys.stdout) as fOut:
            main(fIn, fOut)
0
palswim