Erreur de codage Python Unicode

104

Je lis et analyse un fichier XML Amazon et tandis que le fichier XML affiche un ', lorsque j'essaie de l'imprimer, j'obtiens l'erreur suivante:

'ascii' codec can't encode character u'\u2019' in position 16: ordinal not in range(128) 

D'après ce que j'ai lu en ligne jusqu'à présent, l'erreur vient du fait que le fichier XML est en UTF-8, mais Python veut le gérer comme un caractère encodé ASCII. Existe-t-il un moyen simple de faire disparaître l'erreur et de faire imprimer le XML par mon programme au fur et à mesure?

Alex B
la source
Je venais juste à SO pour poster cette question. Existe-t-il un moyen simple de désinfecter une chaîne unicode()?
Nick Heiner du
Veuillez également vérifier cette réponse à une question connexe: "Python UnicodeDecodeError - Suis-je mal compris encoder?"
tzot le

Réponses:

193

Probablement, votre problème est que vous l'avez bien analysé, et maintenant vous essayez d'imprimer le contenu du XML et vous ne pouvez pas parce qu'il y a des caractères Unicode étrangers. Essayez d'abord d'encoder votre chaîne Unicode en ascii:

unicodeData.encode('ascii', 'ignore')

la partie «ignorer» lui dira de simplement sauter ces caractères. À partir de la documentation Python:

>>> u = unichr(40960) + u'abcd' + unichr(1972)
>>> u.encode('utf-8')
'\xea\x80\x80abcd\xde\xb4'
>>> u.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
UnicodeEncodeError: 'ascii' codec can't encode character '\ua000' in position 0: ordinal not in range(128)
>>> u.encode('ascii', 'ignore')
'abcd'
>>> u.encode('ascii', 'replace')
'?abcd?'
>>> u.encode('ascii', 'xmlcharrefreplace')
'&#40960;abcd&#1972;'

Vous voudrez peut-être lire cet article: http://www.joelonsoftware.com/articles/Unicode.html , que j'ai trouvé très utile comme tutoriel de base sur ce qui se passe. Après la lecture, vous cesserez de vous sentir comme si vous deviez juste quelles commandes utiliser (ou du moins cela m'est arrivé).

Scott Stafford
la source
1
J'essaie de sécuriser la chaîne suivante: 'foo “bar bar” df' (notez les guillemets bouclés), mais ce qui précède échoue toujours pour moi.
Nick Heiner du
@Rosarch: échoue comment? même erreur? Et quelle règle de gestion des erreurs avez-vous utilisée?
Scott Stafford
@Rosarch, votre problème est probablement antérieur. Essayez ce code: # - - codage: latin-1 - - u = u 'foo “bar bar” df' print u.encode ('ascii', 'ignore') Pour vous, il s'agissait probablement de convertir votre chaîne EN unicode donné l'encodage que vous avez spécifié pour le script python qui a généré l'erreur.
Scott Stafford
Je suis allé de l'avant et j'ai fait de mon problème sa propre question: stackoverflow.com/questions/3224427/…
Nick Heiner
1
.encode('ascii', 'ignore')perd des données inutilement même si l'environnement d'OP peut prendre en charge les caractères non-ascii (la plupart des cas)
jfs
16

Une meilleure solution:

if type(value) == str:
    # Ignore errors even if the string is not proper UTF-8 or has
    # broken marker bytes.
    # Python built-in function unicode() can do this.
    value = unicode(value, "utf-8", errors="ignore")
else:
    # Assume the value object has proper __unicode__() method
    value = unicode(value)

Si vous souhaitez en savoir plus sur les raisons:

http://docs.plone.org/manage/troubleshooting/unicode.html#id1

Paxwell
la source
3
Cela n'aide pas avec le problème d'OP: "Impossible d'encoder le caractère u '\ u2019'" . u'\u2019est déjà Unicode.
jfs
6

Ne codez pas en dur le codage des caractères de votre environnement dans votre script; imprimer le texte Unicode directement à la place:

assert isinstance(text, unicode) # or str on Python 3
print(text)

Si votre sortie est redirigée vers un fichier (ou un tube); vous pouvez utiliser PYTHONIOENCODINGenvvar, pour spécifier le codage des caractères:

$ PYTHONIOENCODING=utf-8 python your_script.py >output.utf8

Dans le cas contraire, python your_script.pydevrait fonctionner comme cela est - vos paramètres régionaux sont utilisés pour coder le texte (à l' enregistrement POSIX: LC_ALL, LC_CTYPE, LANGenvvars - ensemble LANGà un lieu utf-8 si nécessaire).

Pour imprimer Unicode sous Windows, consultez cette réponse qui montre comment imprimer Unicode sur la console Windows, dans un fichier ou en utilisant IDLE .

jfs
la source
1

Excellent article: http://www.carlosble.com/2010/12/understanding-python-and-unicode/

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

def __if_number_get_string(number):
    converted_str = number
    if isinstance(number, int) or \
            isinstance(number, float):
        converted_str = str(number)
    return converted_str


def get_unicode(strOrUnicode, encoding='utf-8'):
    strOrUnicode = __if_number_get_string(strOrUnicode)
    if isinstance(strOrUnicode, unicode):
        return strOrUnicode
    return unicode(strOrUnicode, encoding, errors='ignore')


def get_string(strOrUnicode, encoding='utf-8'):
    strOrUnicode = __if_number_get_string(strOrUnicode)
    if isinstance(strOrUnicode, unicode):
        return strOrUnicode.encode(encoding)
    return strOrUnicode
Ranvijay Sachan
la source
0

Vous pouvez utiliser quelque chose du formulaire

s.decode('utf-8')

qui convertira une chaîne d'octets encodée en UTF-8 en une chaîne Python Unicode. Mais la procédure exacte à utiliser dépend exactement de la manière dont vous chargez et analysez le fichier XML, par exemple si vous n'accédez jamais directement à la chaîne XML, vous devrez peut-être utiliser un objet décodeur du codecsmodule .

David Z
la source
Il est déjà codé en UTF-8 L'erreur est spécifiquement: myStrings = deque ([u'Dorf and Svoboda \ u2019s text build on the str ... and Computer Engineering \ u2019s subdisciplines. ']) La chaîne est en UTF-8 comme vous pouvez le voir, mais il s'énerve contre le '\ u2019' interne
Alex B
Oh, OK, je pensais que tu avais un problème différent.
David Z du
7
@Alex B: Non, la chaîne est Unicode, pas Utf-8. Pour l' encoder comme Utf-8, utilisez'...'.encode('utf-8')
qch
0

J'ai écrit ce qui suit pour corriger les citations non-ascii nuisibles et forcer la conversion en quelque chose utilisable.

unicodeToAsciiMap = {u'\u2019':"'", u'\u2018':"`", }

def unicodeToAscii(inStr):
    try:
        return str(inStr)
    except:
        pass
    outStr = ""
    for i in inStr:
        try:
            outStr = outStr + str(i)
        except:
            if unicodeToAsciiMap.has_key(i):
                outStr = outStr + unicodeToAsciiMap[i]
            else:
                try:
                    print "unicodeToAscii: add to map:", i, repr(i), "(encoded as _)"
                except:
                    print "unicodeToAscii: unknown code (encoded as _)", repr(i)
                outStr = outStr + "_"
    return outStr
user5910
la source
0

Si vous avez besoin d'imprimer une représentation approximative de la chaîne à l'écran, plutôt que d'ignorer ces caractères non imprimables, veuillez essayer le unidecodepackage ici:

https://pypi.python.org/pypi/Unidecode

L'explication se trouve ici:

https://www.tablix.org/~avian/blog/archives/2009/01/unicode_transliteration_in_python/

C'est mieux que d'utiliser le u.encode('ascii', 'ignore')pour une chaîne donnée u, et peut vous éviter des maux de tête inutiles si la précision des caractères n'est pas ce que vous recherchez, mais que vous souhaitez toujours avoir une lisibilité humaine.

Wirawan

Wirawan Purwanto
la source
-1

Essayez d'ajouter la ligne suivante en haut de votre script python.

# _*_ coding:utf-8 _*_
Abnvanand
la source
-1

Python 3.5, 2018

Si vous ne connaissez pas le codage mais que l'analyseur Unicode a des problèmes, vous pouvez ouvrir le fichier dans Notepad++et dans la barre supérieure, sélectionnez Encoding->Convert to ANSI. Ensuite, vous pouvez écrire votre python comme ça

with open('filepath', 'r', encoding='ANSI') as file:
    for word in file.read().split():
        print(word)
Atomar94
la source