带有readlines()方法的Python3 UnicodeDecodeError

r_e*_*cur 16 python unicode sys tweepy python-3.x

试图创建一个读取行并发布它们的twitter机器人.使用Python3和tweepy,通过我的共享服务器空间上的virtualenv.这是代码中似乎有问题的一部分:

#!/foo/env/bin/python3

import re
import tweepy, time, sys

argfile = str(sys.argv[1])

filename=open(argfile, 'r')
f=filename.readlines()
filename.close()
Run Code Online (Sandbox Code Playgroud)

这是我得到的错误:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xfe in position 0: ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)

该错误特别指向错误f=filename.readlines()的来源.知道什么可能是错的吗?谢谢.

cal*_*leb 23

我认为最好的答案(在Python 3中)是使用errors=参数:

with open('evil_unicode.txt', 'r', errors='replace') as f:
    lines = f.readlines()
Run Code Online (Sandbox Code Playgroud)

证明:

>>> 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']
>>>
Run Code Online (Sandbox Code Playgroud)

注意,errors=可以是replaceignore.这是ignore看起来像:

>>> with open('evil_unicode.txt', 'r', errors='ignore') as f:
...     lines = f.readlines()
...
>>> lines
['abc\n', 'line2\n', 'line3']
Run Code Online (Sandbox Code Playgroud)


Sha*_*ger 10

您的默认编码似乎是ASCII,其输入很可能是UTF-8.当您在输入中点击非ASCII字节时,它会抛出异常.它readlines本身并不是问题的原因; 相反,它导致读取+解码发生,并且解码失败.

这是一个简单的解决方案; openPython 3中的默认值允许您提供已知encoding的输入,用任何其他可识别的编码替换默认值(在您的情况下为ASCII).提供它允许您继续读取str(而不是显着不同的原始二进制数据bytes对象),同时让Python完成从原始磁盘字节转换为真实文本数据的工作:

# 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()
Run Code Online (Sandbox Code Playgroud)

  • @MH:它适用于*UTF-8 数据*。如果它不是 UTF-8,您需要弄清楚它 * 是 * 什么。这在 3.6.8 上和在任何其他 3.x 版本上一样有效(并且在 Python 2.6+ 上,如果您执行 `from io import open` 以将 Py2 `open` 替换为 Py3 版本)。如果你不知道编码,你就会陷入猜测。 (2认同)

r_e*_*cur -1

最终为自己找到了一个可行的答案:

filename=open(argfile, 'rb')
Run Code Online (Sandbox Code Playgroud)

这篇文章对我帮助很大。

  • 如果您实际上正在使用 Python 3,这将极大地改变您的行为;以二进制模式打开意味着您不仅不会获得行结束翻译(诚然,这只是 Windows 上的一个问题),而且您会返回“bytes”对象而不是“str”(如果您想使用它们,则必须手动“解码”它们) `str`)。我发布了[避免这种情况的答案](http://stackoverflow.com/a/35044042/364696)(假设您知道编码,无论如何您都需要知道编码才能执行“解码”)。 (2认同)