【问题标题】:UnicodeDecodeError when using Python 2.x unicodecsv使用 Python 2.x unicodecsv 时出现 UnicodeDecodeError
【发布时间】:2014-09-23 15:16:27
【问题描述】:

我正在尝试用 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 文本有相当的工作知识,但这让我感到谦卑。

【问题讨论】:

  • encoded_contents 是一个误导性名称。 unicode_text.encode(char_encoding) == bytes_data 和相反的bytes_data.decode(char_encoding) == unicode_textencoded_contents 暗示(错误地)它是 bytes 对象,而不是 unicode

标签: python unicode python-unicode


【解决方案1】:

您应该codecs.open() 用于您的文件。 unicodecsv 包装了 csv 模块,该模块总是将 byte string 写入打开的文件对象。为了将该字节字符串写入一个支持 Unicode 的文件对象,例如由codecs.open() 返回,它被隐式解码;这就是您的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 值进行编码。

【讨论】:

  • 这是正确的,但文件对象(对于支持 Unicode 的插入式 csv 模块替换)应该是二进制的并不明显。它需要一个二进制文件,因为unicodecsvcsv 模块的thin 包装器,仅适用于Python 2 上的二进制数据。否则也可以为文本流定义csv 格式(如JSON) .
  • 但是,不使用 codecs.open() 是绝对要求 == u'unicode sample'.encode('utf-8') == UnicodeDecodeError??
  • @SIslam:如果你的所有数据都是 ASCII 安全的(它将被解码为 ASCII,而不是UTF-8),那么你可以使用codecs.open()。但是,这没什么用。您可以只使用常规文件,而不是 Python 进行无用的解码-编码舞蹈。
猜你喜欢
  • 2019-06-17
  • 2019-01-10
  • 2017-02-23
  • 2022-12-11
  • 2020-05-25
  • 1970-01-01
  • 2011-04-14
  • 1970-01-01
  • 2014-12-15
相关资源
最近更新 更多