UnicodeDecodeError:'ascii'编解码器无法解码字节0xc3,位于第23个位置:序数不在128范围内。

54
当我尝试串联这个时,如果字段包含 'ñ' 或 '´',我会收到 UnicodeDecodeError。如果包含 'ñ' 或 '´' 的字段是最后一个,则不会出现错误。
#...

nombre = fabrica
nombre = nombre.encode("utf-8") + '-' + sector.encode("utf-8")
nombre = nombre.encode("utf-8") + '-' + unidad.encode("utf-8")

#...

return nombre 

有什么想法吗?非常感谢!


可能是重复的问题:Python - 'ascii' codec can't decode byte - bummi
3个回答

64
你正在将文本编码为UTF-8,然后重新编码为UTF-8。Python只能在再次将其解码为Unicode之后才能这样做,但它必须使用默认的ASCII编解码器:
>>> u'ñ'
u'\xf1'
>>> u'ñ'.encode('utf8')
'\xc3\xb1'
>>> u'ñ'.encode('utf8').encode('utf8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

不要一直进行编码;尽可能将编码留到最后,使用连接Unicode值的方式代替。您可以使用str.join()(或者更好地使用unicode.join())来在三个值之间用破折号连接它们。
nombre = u'-'.join(fabrica, sector, unidad)
return nombre.encode('utf-8')

但是即使在这里进行编码可能还为时过早。

经验法则:在接收值的时候解码(如果API没有提供Unicode值),只有在必要时才进行编码(如果目标API无法直接处理Unicode值)。


2
我认为这里的经验法则是关键点。可以这样表述 - “仅在API边界上进行编码和解码,而且只有在必要时才这样做”。 - Michael Anderson
谢谢您的回答。我一直在努力解决这个看似“简单”的转换问题......而您提到的双重编码确实是关键。 - Wing Tang Wong

14

当你遇到一个UnicodeEncodeError错误时,意味着你的代码中有地方将一个字节串直接转换为了一个Unicode字符串。在Python 2中,默认使用ASCII编码,在Python 3中默认使用UTF8编码(这两种编码都可能失败,因为并非所有的字节都是有效的)。

为了避免这种情况,你必须使用显式解码。

如果你的输入文件可能有两种不同的编码方式,其中一种可以接受任何字节(比如UTF8和Latin1),你可以尝试先用第一种编码将字符串转换,如果出现UnicodeDecodeError错误,再使用第二种编码。

def robust_decode(bs):
    '''Takes a byte string as param and convert it into a unicode one.
First tries UTF8, and fallback to Latin1 if it fails'''
    cr = None
    try:
        cr = bs.decode('utf8')
    except UnicodeDecodeError:
        cr = bs.decode('latin1')
    return cr

如果您不知道原始编码并且不关心非 ASCII 字符,可以将 decode 方法的可选参数 errors 设置为 replace。任何有问题的字节都会被替换(来自标准库文档):

使用适当的替换字符进行替换;Python 在解码时将使用官方 U+FFFD 替换字符,并在编码时使用 '?'。

bs.decode(errors='replace')

这并不是直接回答当前问题,而是针对这个问题的一个关闭的重复。至少它是相关的,因为涉及到了一个UnicodeDecodeError错误,而搜索这个错误的用户会找到这个回答... - Serge Ballesta

-9
我在执行python3时遇到了这个错误,但是在python2下执行同样的程序可以正常工作。

降级Python不是解决这个问题的合理方案。 - MarkR

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