Python Unicode CSV导出(使用Django)

问题描述:

我正在使用Django应用程序将字符串导出到CSV文件。该字符串是通过前端表单提交的消息。但是,当输入中提供了一个unicode单引号时,我得到了这个错误。Python Unicode CSV导出(使用Django)

UnicodeEncodeError: 'ascii' codec can't encode character u'\u2019' 
    in position 200: ordinal not in range(128) 

我一直在尝试使用下面的代码将unicode转换为ascii,但仍然得到类似的错误。

UnicodeEncodeError: 'ascii' codec can't encode characters in 
position 0-9: ordinal not in range(128) 

我已经通过几十个网站筛选和学到了很多关于unicode的,但是,我还是没能这个unicode转换为ASCII。我不在乎算法是否删除了unicode字符。注释行表示我尝试过的一些不同的选项,但错误仍然存​​在。

import csv 
import unicodedata 

... 

#message = unicode(unicodedata.normalize(
#       'NFKD',contact.message).encode('ascii','ignore')) 
#dmessage = (contact.message).encode('utf-8','ignore') 
#dmessage = contact.message.decode("utf-8") 
#dmessage = "%s" % dmessage 
dmessage = contact.message 

csv_writer.writerow([ 
     dmessage, 
]) 

有没有人有任何建议去除unicode字符,我可以将它们导出到CSV?这个看似简单的问题让我头晕目眩。任何帮助深表感谢。 谢谢, 乔

+0

感谢修复格伦 – 2010-10-14 01:44:53

您不能将Unicode字符u'\u2019'(U + 2019右单引号)编码为ASCII,因为ASCII中没有该字符。 ASCII只是基本的拉丁字母,数字和标点符号;你不会得到任何重音字母或像这个角色的“聪明引号”。所以你将不得不选择另一种编码。现在通常情况下要做的事情就是导出为UTF-8,UTF-8可以存放任何Unicode字符。不幸的是,如果你的目标用户正在使用Office(他们可能是),他们将无法读取CSV中的UTF-8编码字符。相反,Excel将使用该机器的系统默认代码页(也误导性地称为'ANSI'代码页)读取文件,并且最终得到类似’的mojibake而不是

因此,这意味着如果您希望字符正确显示,您必须猜测用户的系统默认代码页。对于西方用户,这将是代码页1252.与非西方Windows安装的用户将看到错误的字符,但是你没有办法做到这一点(除了组织一封信写作活动给微软放弃愚蠢的废话ANSI已经和其他人一样使用UTF-8)。

代码页1252可以包含U + 2019(),但显然还有更多的字符无法表示。为避免为这些字符获取UnicodeEncodeError,可以使用ignore参数(或replace用问号替换它们)。

dmessage= contact.message.encode('cp1252', 'ignore') 

或者,放弃和删除所有非ASCII字符,这样不管每个人都得到现场的同样糟糕的经历:

dmessage= contact.message.encode('ascii', 'ignore') 
+1

@bobince:“猜测用户的系统默认代码页”......您尝试使用locale.getpreferredencoding()或locale.getdefaultlocale()[1]'来获得权威性的问题? – 2010-10-14 02:35:03

+2

@John:我在想Django是否参与了我们正在讨论的服务器端应用程序,并且不能保证服务器的默认编码与客户端类似。 (在客户端是Windows而服务器不是的情况下,编码永远不会匹配。) – bobince 2010-10-14 02:42:56

+1

@bobince:尽管这个问题没有被指定使用;对于我们所知的所有csv文件可能只是为了持久性目的,并且只能在内部使用。 – 2010-10-14 03:01:15

编码是一种痛苦,但如果你在Django工作你试过从django.utils.encodingsmart_unicode(str)?我发现通常会这样做。

我发现的唯一的其他选择是对字符串使用内置的python encode()decode(),但是您必须为这些指定编码,说实话,这很痛苦。

+0

谢谢,沃夫悖论,我给了smart_unicode一个镜头,让你知道如何继续下去。 – 2010-10-14 01:38:43

[忠告:我不是一个djangoist ; Django可能有更好的解决方案]。

一般非Django的具体回答:

如果你有知非ASCII字符一个很小的数目,并有用户可接受的ASCII等价物对他们来说,你可以建立一个转换表,并使用unicode.translate方法:

smashcii = { 
    0x2019 : u"'", 
    # etc 
    # 

smashed = input_string.translate(smashcii) 
+0

我必须给这个方法一个镜头。至少可以让我通过这个问题。谢谢你的建议。 – 2010-10-14 15:58:54