Python:将Unicode转换为ASCII,不会出现CSV文件错误

6

我一直在StackOverflow上阅读有关Python中将Unicode转换为CSV的所有问题,但仍然感到困惑。每次我收到“UnicodeEncodeError:'ascii'编解码器无法在位置12处对字符u'\xd1'进行编码:序数不在范围内(128)”的错误提示。

buffer=cStringIO.StringIO()
writer=csv.writer(buffer, csv.excel)
cr.execute(query, query_param)
while (1):
    row = cr.fetchone()
    writer.writerow([s.encode('ascii','ignore') for s in row])

row的值为:

(56, u"LIMPIADOR BA\xd1O 1'5 L")

在数据库中,\xd10的值是ñ,这是西班牙语中使用的带变音符号的字母n。起初我尝试将该值转换为ASCII码中有效的内容,但是花费了很多时间后,我只尝试忽略这些字符(我认为带重音的元音字母也会有同样的问题)。

我希望能够保存带有ñ(“LIMPIADOR BAÑO 1'5 L”)的值到CSV文件中,如果不可能,至少能够保存它(“LIMPIADOR BAO 1'5 L”)。


更新,结尾附有问题。 - Sergi
1
为什么不尝试将编码转换为本地的Windows“ANSI”代码页?我猜你正在使用Windows,因为CSV在Windows上最常用,但如果我猜错了,请忽略我的建议。在*NIX操作系统上,我猜8位ISO编码之一可能是合适的,但我不是专家。 - David Heffernan
1个回答

13

正确,ñ不是有效的ASCII字符,因此您无法将其编码为ASCII。所以你可以像你上面的代码一样忽略它们。另一种方法,即去除重音符号,可以在这里找到:What is the best way to remove accents in a Python unicode string?

但要注意,这两种技术都可能导致不良影响,例如使单词实际上意味着不同的东西等。因此最好保留重音符号。然后,您就无法使用ASCII,但可以使用其他编码方式。UTF-8是比较安全的选择。Latin-1或ISO-88591-1是常见的编码方式,但它只包括西欧字符。CP-1252在Windows上很常见,等等。

所以只需将“ascii”替换为您想要使用的任何编码即可。


根据您的注释,您实际的代码如下:

writer.writerow([s.encode('utf8') if type(s) is unicode else s for s in row]) 

在哪里

row = (56, u"LIMPIADOR BA\xd1O 1'5 L")

现在,我认为应该可以工作,但很明显它没有。我想unicode被错误地传递到了cvs writer中。将这一长行分解成它的组成部分:

col1, col2 = row # Use the names of what is actually there instead
row = col1, col2.encode('utf8')
writer.writerow(row) 

现在你的真正错误不会被掩盖,因为你把所有东西都放在同一行。如果你包含了正确的回溯信息,这个问题可能也可以避免。


大多数CSV阅读器无法处理UTF-8。CSV通常在Windows上读取,因此所谓的ANSI编码似乎最合适。 - David Heffernan
我不知道“大多数”,但至少有一些。CSV 到处都在使用。显然需要使用目标软件可以读取的编码。 - Lennart Regebro
问题在于上面的代码使用Unicode字符串u"LIMPIADOR BA\xd1O 1'5 L",但是它会遇到UnicodeEncodeError错误,这个错误也在上面详细说明了("ignore"标志不起作用,我不知道为什么)。在理想情况下,我希望获得一个包含ñ的完整字符串的CSV文件。 - Sergi
@Lennart,抱歉耽搁了,您的评论被隐藏了。您是正确的,代码没问题,错误出在其他地方。事实上,问题在于我写了 writer.writerow([s.encode('utf8') if type(s) is str else s for s in row]) 只对字符串进行编码,而实际上我必须检查unicode if type(s) is unicode。奖励积分。 - Sergi
@Lennart,你说得对,但是请考虑到这一行是从一个元组中通过fetchone查询出来的,所以我在一行中完成了它,以避免在重新编码时将其复制到列表中,然后将值传递给writerow(顺便说一句,我是Python新手;) - Sergi
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接