UnicodeDecodeError:'ascii'编解码器无法解码位置23的字节0xc3:序数不在范围(128)内

54 投票
3 回答
212886 浏览
提问于 2025-04-18 11:28

当我尝试把这些内容连接在一起时,如果字段里有'ñ'或'´',就会出现UnicodeDecodeError的错误。如果包含'ñ'或'´'的字段是最后一个,那就不会出错。

#...

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

#...

return nombre 

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

3 个回答

-9

我在用python3运行时遇到了这个错误,但我只需在 python2 中运行同样的程序就能正常工作。

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')
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)

不要一直进行编码;尽量把编码成UTF-8的操作留到最后一刻再做。可以直接把Unicode值连接起来。

你可以用str.join()(或者说unicode.join())来把三个值用短横线连接起来:

nombre = u'-'.join(fabrica, sector, unidad)
return nombre.encode('utf-8')

不过在这里进行编码可能也太早了。

一个简单的规则是:一收到值就解码(如果不是API已经提供的Unicode值),只有在必须的时候才编码(如果目标API不能直接处理Unicode值)。

撰写回答