2 votes

Erreur de décodage de Python 2.7 en utilisant l'en-tête UTF-8 : UnicodeDecodeError : le codec 'ascii' ne peut pas décoder l'octet 0xc3

Traceback :

Traceback (most recent call last):
  File "venues.py", line 22, in <module>
    main()
  File "venues.py", line 19, in main
    print_category(category, 0)
  File "venues.py", line 13, in print_category
    print_category(subcategory, ident+1)
  File "venues.py", line 10, in print_category
    print u'%s: %s' % (category['name'].encode('utf-8'), category['id'])
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 3: ordinal not in range(128)

Code :

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

# Using https://github.com/marcelcaraciolo/foursquare
import foursquare 

# Prints categories and subcategories
def print_category(category, ident):
    for i in range(0,ident):
        print u'\t',
    print u'%s: %s' % (category['name'].encode('utf-8'), category['id'])

    for subcategory in category.get('categories', []):
        print_category(subcategory, ident+1)

def main():
    client = foursquare.Foursquare(client_id='id',
                                   client_secret='secret')
    for category in client.venues.categories()['categories']:
        print_category(category, 0)

if __name__ == '__main__':
    main()

2voto

Mark Tolonen Points 32702

L'astuce est de garder tout le traitement des chaînes dans le source complètement Unicode. Décodez en Unicode lors de la lecture des entrées (fichiers/pipes/console) et encodez lors de l'écriture des sorties. Si category['name'] est Unicode, gardez-le comme tel (supprimez `.encode('utf8').

Aussi par votre commentaire :

Cependant, l'erreur se produit toujours lorsque j'essaie de faire : python venues.py > categories.txt, mais pas lorsque la sortie va dans le terminal : python venues.py

Python peut généralement déterminer l'encodage du terminal et l'encoder automatiquement, ce qui explique pourquoi l'écriture dans le terminal fonctionne. Si vous utilisez la redirection de l'interpréteur de commandes pour écrire dans un fichier, vous devez indiquer à Python l'encodage d'E/S que vous souhaitez via une variable d'environnement, par exemple :

set PYTHONIOENCODING=utf8
python venues.py > categories.txt

Exemple de travail, en utilisant ma console Windows américaine qui utilise cp437 encodage. Le code source est enregistré en "UTF-8 sans BOM". Il est utile de souligner que le code source sont UTF-8, mais le fait de déclarer l'encodage de la source et d'utiliser une chaîne Unicode dans permet à Python de décoder la source correctement, et d'encoder les octets print sortie automatique vers le terminal en utilisant son encodage par défaut

#coding:utf8
import sys
print sys.stdout.encoding
print u'üéâäàåçêëèïîì'

Ici, Python utilise l'encodage par défaut du terminal, mais lorsqu'il est redirigé, il ne sait pas quel est l'encodage, et utilise donc par défaut le code suivant ascii :

C:\>python example.py
cp437
üéâäàåçêëèïîì

C:\>python example.py >out.txt
Traceback (most recent call last):
  File "example.py", line 4, in <module>
    print u'üéâäàåçêëèïîì'
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-12: ordinal not in range(128)

C:\>type out.txt
None

Puisque nous utilisons la redirection du shell, utilisez une variable shell pour indiquer à Python quel encodage utiliser :

C:\>set PYTHONIOENCODING=cp437

C:\>python example.py >out.txt

C:\>type out.txt
cp437
üéâäàåçêëèïîì

On peut aussi forcer Python à utiliser un autre encodage, mais dans ce cas le terminal ne sait pas comment afficher UTF-8 . Le terminal continue à décoder les octets du fichier à l'aide de la fonction cp437 :

C:\>set PYTHONIOENCODING=utf8

C:\>python example.py >out.txt

C:\>type out.txt
utf8
üéâäàåçêëèïîì

1voto

Armin Rigo Points 4754

Je ne suis pas sûr, mais je pense que le coupable est le caractère "u" au début de u"%s: %s" . Cela suppose que ce que vous voulez imprimer est une chaîne d'octets et non une chaîne unicode --- ce qui serait raisonnable(*) : vous produisez des octets, convenablement codés. Modifié comme ceci :

print '%s: %s' % (category['name'].encode('utf-8'), category['id'])

cela transformerait la chaîne unicode category['name'] en une chaîne d'octets UTF-8, puis le reste du traitement est effectué avec des chaînes d'octets.

(*) C'est raisonnable d'un certain point de vue ; un autre point de vue consiste à imprimer des chaînes unicode et à laisser l'environnement décider de la façon dont elles doivent être encodées, mais vous êtes alors à la merci de plusieurs facteurs que vous ne contrôlez pas vraiment. C'est pourquoi vous voyez des différences entre la sortie vers le terminal ou vers un fichier. Pour éviter tous ces problèmes, il suffit d'imprimer des chaînes d'octets.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X