使用Python 2.x unicodecsv时的UnicodeDecodeError

时间:2014-07-31 15:26:02

标签: 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])

这是追溯:

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)

我认为将它转换为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)
>>> 

到目前为止,我认为我在Python 2.x中使用Unicode文本方面有一定的工作知识,但这让我感到很沮丧。

1 个答案:

答案 0 :(得分:8)

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

使用二进制模式的文件:

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

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

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