如何将utf-8字符写入csv文件?
我的数据和代码:
# -*- coding: utf-8 -*- l1 = ["žžž", "???"] l2 = ["žžž", "???"] thelist = [l1, l2] import csv import codecs with codecs.open('test', 'w', "utf-8-sig") as f: writer = csv.writer(f) for x in thelist: print x for mem in x: writer.writerow(mem)
错误消息:
Traceback (most recent call last): File "2010rudeni priimti.py", line 263, inwriter.writerow(mem) File "C:\Python27\lib\codecs.py", line 691, in write return self.writer.write(data) File "C:\Python27\lib\codecs.py", line 351, in write data, consumed = self.encode(object, self.errors) File "C:\Python27\lib\encodings\utf_8_sig.py", line 82, in encode return encode(input, errors) File "C:\Python27\lib\encodings\utf_8_sig.py", line 15, in encode return (codecs.BOM_UTF8 + codecs.utf_8_encode(input, errors)[0], len(input)) UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 11: ordinal not in range(128)
按任意键继续 ...
我的错是什么?
csv
2.x中的模块不读取/写入Unicode,它读取/写入字节(并假设它们与ASCII兼容,但这不是UTF-8的问题).
所以,当你给它codecs
写一个Unicode文件时,它会传递一个str
而不是一个unicode
.当codecs
尝试使用encode
UTF-8时,它必须首先decode
使用Unicode,因为它使用默认编码,即ASCII,它会失败.因此这个错误:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 11: ordinal not in range(128)
该解决方案在文档中进行了解释,示例中的包装器可以为您处理所有事情.使用UnicodeWriter
带有普通二进制文件,而不是使用codecs
文件.
作为替代方案,PyPI上有一些不同的包csv
可以直接处理模块unicode
而不是str
像unicodecsv
.
作为一个更激进的替代方案,Python 3.x的csv
模块首先没有这个问题(3.x也没有下一个问题).
一个黑客的替代方案就是假装整个世界都是UTF-8.毕竟,你的源代码和你的输出都是UTF-8,并且csv
模块不关心任何东西,只有少数字符(换行符,逗号,可能是引号和反斜杠)是ASCII兼容的.所以你可以完全跳过解码和编码,一切都会好起来的.这里显而易见的缺点是,如果你得到任何错误,而不是得到一个错误来调试,你将得到一个充满垃圾的文件.
您的代码还有另外两个问题,无论是哪个UnicodeWriter
还是unicodecsv
可以神奇地修复(尽管Python 3可以修复第一个).
首先,你没有真正给了csv
摆在首位模块的Unicode.源数据中的列是普通的旧str
文字,例如"žžž"
.您无法将其编码为UTF-8,或者您可以,但只能通过自动将其解码为ascii,这将再次导致相同的错误.使用Unicode文字,比如u"žžž"
,以避免这种情况(或者,如果您愿意,可以decode
从源代码编码中明确表示......但这有点愚蠢).
其次,您没有在源中指定编码声明,但是您使用了非ASCII字符.从技术上讲,这在Python 2.7中是非法的.实际上,我很确定它会给你一个警告,但后来将你的来源视为Latin-1.这很糟糕,因为你显然没有使用Latin-1编辑器(你不能放入ž
Latin-1文本文件,因为没有这样的字符).如果您将文件保存为UTF-8,然后告诉Python将其解释为Latin-1,那么您最终将使用žžž
而不是žžž
类似的mojibake.