web-dev-qa-db-fra.com

Python3 UnicodeDecodeError avec la méthode readlines ()

Essayer de créer un bot Twitter qui lit les lignes et les poste. En utilisant Python3 et tweepy, via un virtualenv sur mon espace serveur partagé. C'est la partie du code qui semble avoir des problèmes:

#!/foo/env/bin/python3

import re
import tweepy, time, sys

argfile = str(sys.argv[1])

filename=open(argfile, 'r')
f=filename.readlines()
filename.close()

c'est l'erreur que j'obtiens:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xfe in position 0: ordinal not in range(128)

L'erreur pointe spécifiquement sur f=filename.readlines() comme source de l'erreur. Une idée de ce qui pourrait être faux? Merci.

10
r_e_cur

Je pense que la meilleure réponse (en Python 3) est d'utiliser le paramètre errors=:

with open('evil_unicode.txt', 'r', errors='replace') as f:
    lines = f.readlines()

Preuve:

>>> s = b'\xe5abc\nline2\nline3'
>>> with open('evil_unicode.txt','wb') as f:
...     f.write(s)
...
16
>>> with open('evil_unicode.txt', 'r') as f:
...     lines = f.readlines()
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/codecs.py", line 319, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe5 in position 0: invalid continuation byte
>>> with open('evil_unicode.txt', 'r', errors='replace') as f:
...     lines = f.readlines()
...
>>> lines
['�abc\n', 'line2\n', 'line3']
>>>

Notez que le errors= peut être replace ou ignore. Voici à quoi ressemble ignore:

>>> with open('evil_unicode.txt', 'r', errors='ignore') as f:
...     lines = f.readlines()
...
>>> lines
['abc\n', 'line2\n', 'line3']
17
caleb

Votre codage par défaut semble être ASCII, où l'entrée est plus que probable UTF-8. Lorsque vous frappez des octets non-ASCII dans l'entrée, l'exception est levée. Ce n'est pas tant que readlines soit lui-même responsable du problème; au contraire, le décodage lecture + se produit et le décodage échoue.

C'est une solution facile cependant; La valeur par défaut open dans Python 3 vous permet de fournir la encoding connue d'une entrée, en remplaçant la valeur par défaut (ASCII dans votre cas) par tout autre codage reconnu. Cela vous permet de continuer à lire en tant que str (plutôt que les objets bytes de données binaires brutes très différents), tout en laissant Python se charger de la conversion d'octets de disque brut en données en texte vrai:

# Using with statement closes the file for us without needing to remember to close
# explicitly, and closes even when exceptions occur
with open(argfile, encoding='utf-8') as inf:
    f = inf.readlines()
8
ShadowRanger

J'ai fini par trouver une solution de travail pour moi-même:

filename=open(argfile, 'rb')

Ce post m'a beaucoup aidé.

0
r_e_cur