我正在阅读的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行,我也会得到同样的错误。
答案 0 :(得分:19)
围绕所有“'ascii'编解码器无法编码字符...”的一个非常简单的方法csvwriter的问题是改为使用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)
答案 1 :(得分:10)
为了它的价值:我是xlrd
的作者。
xlrd
是否产生unicode?
选项1:阅读第一个xlrd
doc屏幕底部的Unicode部分:此模块将所有文本字符串显示为Python unicode对象。
选项2:print type(text), repr(text)
你说“”“如果我把它重写为x.encode('utf-8')它会停止抛出一个错误,但不幸的是当我把数据写到其他地方(如latin-1)时,£符号所有都变得乱码。“”“当然如果你把UTF-8编码的文本写入一个期望latin1的设备,它将是乱码。你有什么期望?
你在编辑中说:“”“即使我取消注释Latin-1行”“”我也会得到同样的错误。这是非常不可能的 - 更有可能的是你在不同的源代码行(未注释的latin1行而不是writerow行)中出现了稍微不同的错误(提到latin1编解码器而不是ascii编解码器)。仔细阅读错误信息有助于理解。
你的问题是,一般来说你的数据不能用latin1编码;现实世界的数据很少。你的POUND SIGN可以在latin1中编码,但这不是你所有的非ASCII数据。有问题的角色是U + 2022 BULLET,在latin1中无法编码。
如果您事先提到过您在Mac OS X上工作,那么它会帮助您尽快得到更好的答案...对于适合CSV的编码的常见疑问是cp1252
(Windows),而不是mac-roman
。
答案 2 :(得分:9)
您的代码段显示x.decode
,但您收到编码错误 - 意味着x
已经是Unicode,因此,为了“解码”它,它必须首先变成一个字节串(这是默认编解码器ansi
出现并失败的地方)。在你的文字中你会说“如果我重写为x。编码”......这似乎暗示你做知道x是Unicode。
那么你正在做什么 - 以及你意味着做什么 - 编码一个unicode x
以获得一个编码的字节串,或解码一个将字符串转换为unicode对象?
我觉得很遗憾,你可以在一个字节字符串上调用encode
,在unicode对象上调用decode
,因为我发现它似乎只引起用户混淆......但至少在这种情况下,你似乎设法传播混乱(至少对我来说; - )。
如果看起来x
是unicode,那么你永远不想“解码”它 - 你可能想要编码它以获得带有某个编解码器的字节串,例如latin-1,如果这就是你需要的某种I / O目的(对于你自己的内部程序使用,我建议一直坚持使用unicode - 只有当你绝对需要或接收,用于输入/输出目的的编码字节字符串。)
答案 3 :(得分:5)
x = x.decode("ISO-8859-1")
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa3' in position 0: ordinal not in range(128)
仔细观察:你有一个Unicode ***编码***错误调用解码方法。
原因是decode
旨在从字节序列(str
)转换为unicode
对象。但是,正如约翰所说,xlrd
已使用Unicode字符串,因此x
已经是unicode
对象。
在这种情况下,Python 2.x假定您意味着来解码str
对象,因此它“帮助”为您创建一个。但是为了将unicode
转换为str
,它需要编码,并选择ASCII,因为它是字符编码的最小公分母。您的代码有效地被解释为
x = x.encode('ascii').decode("ISO-8859-1")
失败,因为x
包含非ASCII字符。
由于x
已经是unicode
个对象,因此decode
是不必要的。但是,现在您遇到了Python 2.x csv
模块不支持Unicode的问题。您必须将数据转换为str
个对象。
for item in items:
item = [x.encode('latin-1') for x in item]
cleancsv.writerow(item)
这是正确的,除了你的数据中有•
个字符(U + 2022 BULLET),而Latin-1不能代表它。有几种方法可以解决这个问题:
x.encode('latin-1', 'ignore')
删除子弹(或其他非拉丁字符1)。x.encode('latin-1', 'replace')
,用问号替换子弹。*
或·
这样的Latin-1字符替换项目符号。目前,UTF-8受到广泛支持,因此几乎没有理由对文本文件使用任何其他编码。
答案 4 :(得分:2)
xlrd
适用于Unicode,因此您获取的字符串是Unicode字符串。 £ - 符号的代码点为U + 00A3,因此所述字符串的表示应为u'\xa3'
。这已被正确读入;它是你应该在整个程序中使用的字符串。
当你在某处写这个(抽象,Unicode)字符串时,你需要选择一个编码。此时,您应.encode
进入该编码,例如latin-1
。
>>> book = xlrd.open_workbook( "test.xls" )
>>> sh = book.sheet_by_index( 0 )
>>> x = sh.cell_value( 0, 0 )
>>> x
u'\xa3'
>>> print x
£
# sample outputs (for e.g. writing to a file)
>>> x.encode( "latin-1" )
'\xa3'
>>> x.encode( "utf-8" )
'\xc2\xa3'
# garbage, because x is already Unicode
>>> x.decode( "ascii" )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa3' in position 0:
ordinal not in range(128)
>>>
答案 5 :(得分:0)
使用xlrd,我有一行...... xl_data.find(str(cell_value))...它给出了错误:“'ascii'编解码器不能编码位置3中的字符u'\ xdf' :序数不在范围内(128)“。论坛中的所有建议对我的德语单词都没用。但改成:... xl_data.find(cell.value)...没有错误。因此,我认为在某些命令中使用字符串作为参数,xldr具有特定的编码问题。