UnicodeEncodeError:'ascii'编解码器无法编码字符u'\ xa3'

时间:2010-08-27 20:59:08

标签: python character-encoding

我正在阅读的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 个答案:

答案 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具有特定的编码问题。