使用Python 2.x unicodecsv时的UnicodeDecodeError

Sco*_*ott 8 python unicode python-unicode

我正在尝试用Unicode字符写出一个csv文件,所以我使用的是unicodecsv包.不幸的是,我仍然得到UnicodeDecodeErrors:

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

import codecs
import unicodecsv

raw_contents = 'He observes an “Oversized Gorilla” near Ashford'
encoded_contents = unicode(raw_contents, errors='replace')

with codecs.open('test.csv', 'w', 'UTF-8') as f:
    w = unicodecsv.writer(f, encoding='UTF-8')
    w.writerow(["1", encoded_contents])
Run Code Online (Sandbox Code Playgroud)

这是追溯:

Traceback (most recent call last):
  File "unicode_test.py", line 11, in <module>
    w.writerow(["1", encoded_contents])
  File "/Library/Python/2.7/site-packages/unicodecsv/__init__.py", line 83, in writerow
    self.writer.writerow(_stringify_list(row, self.encoding, self.encoding_errors))
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/codecs.py", line 691, in write
    return self.writer.write(data)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/codecs.py", line 351, in write
    data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xef in position 17: ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)

我认为将它转换为Unicode就足够了,但事实并非如此.我真的很想了解发生了什么,以便我更好地准备在将来的其他项目中处理这些错误.

从追溯,看起来我可以像这样重现错误:

>>> raw_contents = 'He observes an “Oversized Gorilla” near Ashford'
>>> raw_contents.encode('UTF-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 15: ordinal not in range(128)
>>> 
Run Code Online (Sandbox Code Playgroud)

到目前为止,我认为我在Python 2.x中使用Unicode文本方面有相当的工作知识,但这让我很谦卑.

Mar*_*ers 8

你应该使用codecs.open()为您的文件.unicodecsv包装csv模块,该模块始终将字节字符串写入打开的文件对象.为了将该字节字符串写入支持Unicode的文件对象(如返回的)codecs.open(),它被隐式解码 ; 这是您的UnicodeDecodeError例外源自的地方.

改为使用二进制模式的文件:

with open('test.csv', 'wb') as f:
    w = unicodecsv.writer(f, encoding='UTF-8')
    w.writerow(["1", encoded_contents])
Run Code Online (Sandbox Code Playgroud)

除非您的数据包含嵌入的换行符,否则二进制模式不是必需的,但csv模块希望控制如何写入换行符以确保正确处理这些值.但是,不使用codecs.open()是绝对必要的.

调用.encode()字节字符串时会发生同样的事情; 你已经在那里编码了数据,因此Python隐式解码以获得要编码的Unicode值.