2013-08-05 51 views
1

当试图在Python中将数据写入CSV时,我收到以下错误。如何在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'} 

我知道你不能写的unicode与Python中的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

我通常只是使用https://github.com/jdunck/python-unicodecsv –

+0

请不要只发布没有追踪的错误消息。你的代码中至少有三条不同的线,可能来自错误,也许更多;如果我不知道它来自哪一个实体,那么很难调试它。 (另外,运行您发布的代码时发布的示例数据是否真的会出错?) – abarnert

回答

7

你不能写的Unicode到CSV ...但你可以写恰巧是UTF-8(或Latin-1的,或者几乎任何其它编码*)编码的Unicode字节。 The docs明确地说,这一点,并建议如何对付它:

Note: This version of the csv module doesn’t support Unicode input. Also, there are currently some issues regarding ASCII NUL characters. Accordingly, all input should be UTF-8 or printable ASCII to be safe; see the examples in section Examples. These restrictions will be removed in the future.

Examples section展示了如何解决这个问题,提供让您阅读并自动为你写unicode对象,编码/解码UTF-8封装。如果您使用的是不同的字符集(例如,因为您计划将此字符传递给需要cp1252编码的CSV的Excel VBscript),请根据需要替换'utf-8'


的示例代码做一些花哨的脚法,以确保该csv模块本身只具有处理UTF-8,而该文件可以在不同的编解码器。这是处理可能会混淆csv模块的编解码器的好方法。但看起来你只是在寻找Latin-1(或像cp1252这样的Latin-1扩展字符集),或者甚至是UTF-8本身。在这种情况下,你可以只使用一个快速&肮脏的解决方案,如:

w.writerows(mydata) 

...你可以做这样的事情哈克:

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'), … 

如果你不知道你想要写的那种事......嗯,你可以” t做快速的&肮脏的解决方案。


在你编辑的版本,您使用的快速&肮脏的解决方案是这样的:

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字节串,如'Blah \xc3\x93 D\xc3\xa1blah'。也可能有一些数字或内容,或者你只是小心点。

无论如何,这是不会工作; UTF-8编码的字符串将通过str不变,解码为sys.getdefaultencoding(),并重新编码为UTF-8,而Unicode字符串将使用默认编码进行编码,使用默认编码进行解码,并使用UTF-8重新编码。

如果这是你的实际数据,代码将是这样的:

def utf8ify_s(s): 
    if isinstance(s, unicode): 
     return s.encode('utf-8') 
    else: 
     return str(s) 

这将编码unicode字符串,假设str串已经在UTF-8,并通过他们通过str(这将离开他们不变),并通过调用str(这对任何内置类型都很好,并且只要您编写的自定义类型为'str是纯ASCII或UTF-8,它们也可以),将数字等转换为字符串。然后,而不是str(…).encode('utf-8')每个kv,调用这个函数:

def utf8ify(d): 
    return dict(utf8ify_s(k): utf8ify_s(v) for k, v in d.iteritems()) 

同时,我会强烈建议您通过Unicode HOWTO阅读,你还需要什么,了解什么是真正回事这里,而不是只是试图破解你的代码,直到它似乎工作。


*实际规则是这样的:没有内嵌的NULL字节(所以UTF-16出),可以跨越多行不持久状态(这样一些东亚编码都出来了),没有“代理“式部分字符字节,与您的引用字符的字节匹配。如果你不确定...使用花哨的转换器并通过UTF-8。

+0

尝试此操作时,收到错误“UnicodeDecodeError:'ascii'编解码器无法解码位置7中的字节0xc3:序数不在范围内(128)“ – JStew

+0

@Jtetew:这样的评论对调试完全没用。尤其是在回答提出两个或更多解决方案的答案时,“试用此方法”并不能告诉我们您尝试了什么。即使答案只有一个解决方案,它仍然不会告诉我们您的确切代码。没有回溯的错误,或者至少是它所源自的代码行也是无用的。 – abarnert

+0

我用我试过的东西编辑了我原来的问题。我还尝试在运行脚本之前以UTF-8保存我的CSV。 – JStew