UnicodeEncodeError: 'ascii' 编码无法编码字符 u'\xa3
我有一个Excel表格,里面有一些英镑符号(£)。
当我用xlrd这个模块读取它的时候,出现了一个错误:
x = table.cell_value(row, col)
x = x.decode("ISO-8859-1")
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa3' in position 0: ordinal not in range(128)
如果我把这段代码改成x.encode('utf-8'),错误就不出现了,但问题是,当我把数据写到其他地方(用latin-1编码)时,英镑符号都变得乱七八糟了。
我该怎么做才能正确读取英镑符号呢?
--- 更新 ---
有些热心的朋友建议我根本不需要解码,或者只在需要的时候把它编码成Latin-1。问题是,我最终需要把数据写入一个CSV文件,而这个文件似乎对原始字符串有些不满。
如果我根本不对数据进行编码或解码,那么在我把字符串添加到一个叫做items的数组后,就会出现这样的情况:
for item in items:
#item = [x.encode('latin-1') for x in item]
cleancsv.writerow(item)
File "clean_up_barnet.py", line 104, in <module>
cleancsv.writerow(item)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2022' in position 43: ordinal not in range(128)
即使我取消注释Latin-1那一行,错误依然会出现。
6 个回答
说实话,我是 xlrd
的作者。
xlrd
能生成 Unicode 吗?
选项 1:看看 xlrd
文档第一页底部的 Unicode 部分:这个模块把所有文本字符串都当作 Python 的 Unicode 对象来处理。
选项 2:用 print type(text), repr(text)
来检查一下。
你说:“如果我把这个改成 x.encode('utf-8'),就不再报错了,但不幸的是,当我把数据写到别的地方(用 latin-1 编码)时,£ 符号都变得乱七八糟。”当然啦,如果你把 UTF-8 编码的文本写到一个期待 latin1 的地方,肯定会出问题。你还指望什么呢?
你在编辑中说:“即使我取消注释 Latin-1 的那一行,我也会得到同样的错误。”这不太可能——更有可能的是你在不同的代码行上遇到了稍微不同的错误(提到的是 latin1 编码而不是 ascii 编码)。仔细阅读错误信息会帮助你更好地理解问题。
你这里的问题是,通常情况下你的数据是不能用 latin1 编码的;现实中能用的很少。你的英镑符号是可以用 latin1 编码的,但这并不是你所有非 ASCII 数据的情况。问题字符是 U+2022 BULLET,这个是不能用 latin1 编码的。
如果你一开始就提到你是在 Mac OS X 上工作,可能会更快得到更好的答案……通常适合 CSV 的编码是 cp1252
(Windows),而不是 mac-roman
。
解决所有“'ascii' 编码无法编码字符…”这类问题的一个非常简单的方法是使用 unicodecsv,它可以直接替代 csvwriter。
你可以通过 pip 安装 unicodecsv,然后就可以用和之前完全一样的方式来使用它,比如:
import unicodecsv
file = open('users.csv', 'w')
w = unicodecsv.writer(file)
for user in User.objects.all().values_list('first_name', 'last_name', 'email', 'last_login'):
w.writerow(user)
你的代码片段中提到 x.decode
,但你却遇到了一个编码错误,这意味着 x
已经是 Unicode 格式了。所以,要“解码”它,首先得把它转换成字节串(这就是为什么默认的编码方式 ansi
会出现问题)。然后你在文本中说“如果我把它改成 x.encode”...这似乎表明你知道x是Unicode格式。
那么你实际上在做什么——以及你想要做什么——是把一个 Unicode 的 x
编码成一个字节串,还是把一个字节串解码成一个 Unicode 对象呢?
我觉得很遗憾的是,你可以在字节串上调用 encode
,在 Unicode 对象上调用 decode
,因为这似乎让用户感到困惑……但至少在这种情况下,你似乎也在传播这种困惑(至少对我来说是这样;-)。
如果 x
确实是 Unicode,那你就不需要“解码”它——你可能想要编码它,以便得到一个使用特定编码方式的字节串,比如 latin-1,如果这是你在某种输入/输出场景中需要的(对于你自己内部程序的使用,我建议始终使用 Unicode——只有在绝对需要或接收到字节串用于输入/输出时,才进行编码/解码)。