Python Unicode CSV导出(使用Django)

Python Unicode CSV导出(使用Django),python,unicode,utf-8,csv,ascii,Python,Unicode,Utf 8,Csv,Ascii,我正在使用Django应用程序将字符串导出到CSV文件。字符串是通过前端表单提交的消息。然而,当输入中提供unicode单引号时,我遇到了这个错误 UnicodeEncodeError: 'ascii' codec can't encode character u'\u2019' in position 200: ordinal not in range(128) 我一直在尝试使用下面的代码将unicode转换为ascii,但仍然遇到类似的错误 UnicodeEncodeError: '

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

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?这个看似简单的问题让我头晕目眩。非常感谢您的帮助。 谢谢
Joe

编码是一件痛苦的事,但是如果你在django工作,你有没有从
django.utils.Encoding
尝试过
smart\u unicode(str)
?我发现这通常能奏效


我发现的另一个选择是对字符串使用内置python
encode()
decode()
,但是你必须为这些字符串指定编码,老实说,这是一件痛苦的事情。

你不能将Unicode字符
u'\u2019'
(u+2019右单引号)编码成ASCII,因为ASCII没有这个字符。ASCII只是基本的拉丁字母、数字和标点符号;你不会得到任何像这个字符一样的重音字母或“智能引号”

因此,您必须选择另一种编码。现在通常明智的做法是导出到UTF-8,它可以保存任何Unicode字符。不幸的是,如果您的目标用户正在使用Office(他们可能正在使用),他们将无法读取CSV中的UTF-8编码字符。相反,Excel将使用该机器的系统默认代码页(也称为“ANSI”代码页)读取文件,并以类似mojibake的
结束™而不是

因此,这意味着如果希望字符正确显示,您必须猜测用户的系统默认代码页。对于西方用户,这将是代码页1252。使用非西方Windows安装的用户将看到错误的字符,但对此你无能为力(除了组织一次写信给微软的活动,让微软不再使用ANSI,像其他人一样使用UTF-8)

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

或者,放弃并删除所有非ASCII字符,这样无论语言环境如何,每个人都会得到同样糟糕的体验:

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

[警告:我不是django主义者;django可能有更好的解决方案]

一般非django特定答案:

如果已知的非ASCII字符数量很少,并且存在用户可接受的ASCII等效字符,则可以设置转换表并使用
unicode.translate
方法:

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

smashed = input_string.translate(smashcii)

谢谢Waffel Paradox,我会给smart_unicode一个机会,让你知道这是怎么回事。谢谢你的修复Glenn@bobince:“猜测用户的系统默认代码页”。。。您在尝试使用
locale.getpreferredencoding()
locale.getdefaultlocale()[1]
获得此授权时遇到了哪些问题?@John:我想如果涉及Django,我们谈论的是一个服务器端应用程序,无法保证服务器的默认编码与客户端的类似。(在客户端是Windows而服务器不是Windows的常见情况下,编码将永远不会匹配。)@bobince:问题从未指定用途;据我们所知,csv文件只能用于持久性目的,只能在内部使用。@bobince:oh。下一个问题:那么这个django gadjet不知道用户的区域设置,也无法获得它?不,无法访问用户对webapp的默认编码。您可以从用户的首选语言和使用客户端脚本的用户浏览器安装语言(如果使用IE,则为操作系统语言)的组合中进行猜测,如果您想获得真正的乐趣,可以加载任何编码的HTML文件,并查看浏览器猜测的编码。但所有这些都是不同的设置,并且可能经常出错。如果您必须支持“ANSI”代码页,唯一可靠的方法是明确地询问用户。我必须尝试一下这种方法。至少可以帮我解决这个问题。谢谢你的建议。
smashcii = {
    0x2019 : u"'",
    # etc
    #

smashed = input_string.translate(smashcii)