尝试在Python中将数据写入CSV时,收到以下错误。
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/csv.py", line 150, in writerows
UnicodeEncodeError: 'ascii' codec can't encode character u'\xd3' in position 0: ordinal not in range(128)
以下是我尝试写入CSV的字典示例:
{'Field1': 'Blah \xc3\x93 D\xc3\xa1blah', 'Field2': u'\xd3', 'Field3': u'Blah', 'Field4': u'D\xe1blah'}
我知道您无法使用Python将Unicode写入CSV,但我无法确定要转换的内容以及如何转换它。
修改:这是我尝试过的。 dictList
是从另一个CSV中获取的词典列表。
WANTED_HEADERS = ['First Name',
'Last Name',
'Date',
'ID']
def utf8ify(d):
return dict((str(k).encode('utf-8'), str(v).encode('utf-8')) for k, v in d.iteritems())
def ListToCSVWithHeaders(data_list, output_file_name, headers):
output_file = open(output_file_name, 'w')
header_row = {}
to_append = []
for entry in data_list:
to_append.append(utf8ify(entry))
for key in entry.keys():
if key not in headers:
headers.append(key)
print 'KEY APPENDED: ' + key
for header in headers:
header_row[header] = header
data = [header_row]
data.extend(to_append)
data_writer = csv.DictWriter(output_file, headers)
data_writer.writerows(data)
print str(len(data)) + ' rows written'
ListToCSVWithHeaders(dictList, 'output.csv', WANTED_HEADERS)
这是我在运行时收到的错误。
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 7: ordinal not in range(128)
答案 0 :(得分:8)
您不能将Unicode写入CSV ...但您可以编写恰好是UTF-8(或Latin-1,或几乎任何其他编码*)编码Unicode的字节。 The docs明确说出这一点,并建议如何处理它:
注意:此版本的
csv
模块不支持Unicode输入。此外,目前有一些关于ASCII NUL字符的问题。因此,所有输入应为UTF-8或可打印的ASCII以确保安全;请参阅示例部分中的示例。这些限制将在未来删除。
Examples section显示如何处理此问题,提供包装器,让您自动读取和写入unicode
个对象,自动编码/解码UTF-8。如果您正在使用不同的字符集(例如,因为您计划将其传递给需要cp1252编码的CSV的Excel VBscript),请根据需要替换'utf-8'
。
示例代码做了一些花哨的步法,以确保csv
模块本身只需要处理UTF-8,而文件可以在不同的编解码器中。这是处理可能会混淆csv模块的编解码器的好方法。但看起来你只是在寻找Latin-1(或者像cp1252这样的拉丁语1扩展字符集),甚至可能是UTF-8本身。在这种情况下,您可以使用快速和肮脏的解决方案,如下所示:
w.writerows(mydata)
...你可以像这样做一些hacky:
def utf8ify(d):
return dict((k.encode('utf-8'), v.encode('utf-8')) for k, v in d.iteritems())
w.writerows(utf8ify(d))
根据您尝试编写的值,您可能需要更改上述内容。例如,如果原始字典中有Latin-1字符串,则需要以下内容:
k.decode('latin-1').encode('utf-8'), …
如果你不知道你想写的那种东西......好吧,你不能做快速和彻底的解决方案。
在您编辑的版本中,您正在以这种方式使用快速和肮脏的解决方案:
def utf8ify(d):
return dict((str(k).encode('utf-8'), str(v).encode('utf-8')) for k, v in d.iteritems())
...您传递的值似乎是unicode
字符串的混合,如u'\xd3'
和我认为是UTF-8编码的str
字节字符串,如{{1} }。那里可能还有一些数字或某些东西,或者你可能只是小心。
无论如何,那是行不通的; UTF-8编码的字符串将通过'Blah \xc3\x93 D\xc3\xa1blah'
未更改,解码为str
,并重新编码为UTF-8,而Unicode字符串将使用默认编码进行编码,使用默认编码进行解码,并用UTF-8重新编码。
如果这是您的实际数据,代码将是这样的:
sys.getdefaultencoding()
这将编码def utf8ify_s(s):
if isinstance(s, unicode):
return s.encode('utf-8')
else:
return str(s)
字符串,假设unicode
字符串已经是UTF-8并通过str
传递(这将使它们保持不变),并将数字等转换为字符串通过调用str
(对于任何内置类型都可以,并且只要您编写的自定义类型'str
是纯ASCII或UTF-8,它们也适合它们)。然后,对每个str
和str(…).encode('utf-8')
而不是k
,请调用此函数:
v
与此同时,我强烈建议您仔细阅读Unicode HOWTO以及您需要的任何其他内容,以了解其中的实际内容,而不仅仅是尝试破解代码,直到它看起来有效。< / p>
*实际规则是这样的:没有嵌入的NUL字节(因此UTF-16已经出局),没有可以跨越多行的持久状态(因此一些东亚编码已经出局),并且没有“代理”式与引号字符的字节匹配的部分字符字节。如果您不确定...使用花式转换器并通过UTF-8。