【问题标题】:Python, UnicodeDecodeError trying to print exception that contains non ascii charsPython,UnicodeDecodeError 试图打印包含非 ascii 字符的异常
【发布时间】:2015-02-23 12:15:08
【问题描述】:

当我收到cPickle.UnpicklingError: invalid load key, 'ÿ'. 的异常并尝试打印它时,当我尝试将它插入到我的(unicode)错误消息中时,它会引发一个 unicode 解码错误:

try:
    settings = _load()
except cPickle.UnpicklingError, err:
    msg = _(u"Error reading ... (the error is: '%s')")
    cont = askYes(msg % err, _(u"Settings Load Error")) # raises

尝试了msg % unicode(err.message, encoding='utf-8') 中的解决方法,但显然err.message 不是有效的Unicode 字符串(“UnicodeDecodeError: 'utf8' codec can't decode byte 0xff in position 19: invalid start byte”)

那么处理这个问题的最 Pythonic 方式是什么?我应该将“忽略”或“替换”传递给unicode() 吗?

编辑:askYes(None, msg % repr(err), _(u"Settings Load Error")) 给出如下内容:

(the error is: 'UnpicklingError("invalid load key, '\xff'.",)'). # ff is ÿ

不吹,但仍然...

Edit2:我报告的错误有点与人为的混淆:

u'%s' % "cPickle.UnpicklingError: invalid load key, 'ÿ'."
Traceback (most recent call last):
  File "<input>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 44: ordinal \
    not in range(128)

这是来自 pycharm 内部的解释器 - 显然 ÿ'\xc3\xbf' 那里 (...)

【问题讨论】:

  • 使用repr,或者更直接地使用%r而不是%s,是显示可疑内容字符串的最佳方式——它可能或可能不是用来表示Unicode,但您显示的\x0f 或您之前提到的0xff 都会对编码进行思考。如果err.message 是一个没有韵律或理由的随机字节集合,你怎么能比repr 更好地显示它?! ignorereplace 会隐藏潜在的宝贵信息以用于调试目的 - 切勿在错误消息中这样做!
  • @AlexMartelli:谢谢-是的,我不会使用替换和合作-我只是想吓唬人们,所以他们回答我:D。您能否详细说明repr - 使用 repr(err.message) 会更好吗?我会很感激一个完整的答案
  • @AlexMartelli: repr(err.message): (the error is: '"invalid load key, '\x0f'."') 而 repr(err): (the error is: 'UnpicklingError("invalid load key, '\x0f'.",)')。我宁愿在`(错误是:UnpicklingError:“无效的加载键,'\x0f'。”)'行中有一些东西-我必须手动构造它吗?我也承认 为什么repr() 设法解码字符串让我无法理解
  • 字符串中似乎没有任何 Unicode 问题,如下所示:'\x0f' 没有出现这样的问题——而'\xff' 会出现。尝试将 err.message 解码为“iso-8859-1”,这不会失败(它会解码每个字节,尽管可能会解码为无意义的字形),您可能会了解更多信息。顺便说一句,repr 没有问题也就不足为奇了——repr 永远不会失败——让我困惑的是 '\xff''\x0f' 之间的炼金术转换!
  • @AlexMartelli: 抱歉-我可能已经转换了错误消息-显然err.message 在“UnicodeDecodeError: 'utf8' codec...position 19”中是invalid load key, ' + chr(0xff)。为什么 repr 永远不会失败?它使用 iso-8859-1 吗?

标签: python python-2.7 unicode encoding utf-8


【解决方案1】:

只是为了澄清一些观点:

Python 2.7.8 (default, Jun 30 2014, 16:03:49) [MSC v.1500 32 bit (Intel)] on win32
>>> u'%s' % "cPickle.UnpicklingError: invalid load key, 'ÿ'."
Traceback (most recent call last):
  File "<input>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 44: ordinal not in range(128)

这是因为 python 2 有用地尝试解码字符串以将其插入 unicode 字符串 - 默认编码是 ASCII - 当然 ascii 无法解码 'ÿ' (解码意味着将字节转换为代码点) - 因此例外。下面的作品因为它不尝试解码任何东西 - 只是显示字节 - 在 ascii 中:

>>> '%s' % "cPickle.UnpicklingError: invalid load key, 'ÿ'."
"cPickle.UnpicklingError: invalid load key, '\xc3\xbf'."

下面也可以工作,并且(如控制台在 ascii 中显示)显示 unicode 字节值(即 编码 unicode 字符串 - 那里的字节 - 到 ascii 字符):

>>> u'%s' % u"cPickle.UnpicklingError: invalid load key, 'ÿ'."
u"cPickle.UnpicklingError: invalid load key, '\xff'."

与以下逻辑相同:

>>> u'á, é, í, ó, ú, ü, ñ'
u'\xe1, \xe9, \xed, \xf3, \xfa, \xfc, \xf1'
>>> 'á, é, í, ó, ú, ü, ñ'
'\xc3\xa1, \xc3\xa9, \xc3\xad, \xc3\xb3, \xc3\xba, \xc3\xbc, \xc3\xb1'

正是这种内部编码/解码让我感到困惑 - 仍然让我有些困惑。

【讨论】:

    【解决方案2】:

    确保您可以在错误消息中看到结果的一种方法是使用repr,或更直接地使用%r 而不是%s:这永远不会失败(因为任何对象都有表示,并且所有表示都是在 ASCII 中,包括可能的转义序列),并且还显示(作为转义序列)可能不可见的字符。

    repr(以及旧式格式字符串中的'%r')委托给对象类型的__repr__ 特殊方法;每个对象类型负责知道如何以明确的(不一定是超级可读的)ASCII 字符串来最好地表示自己。字符串和字节序列特别擅长这一点,所以repr 非常适合它们。

    OP 已经做到了,但不喜欢结果的美感(在 err.messagereprerrrepr 之间变化)。不幸的是,美学对于repr 来说是最不重要的:相反,这完全是关于完整、明确的信息。

    另一个想法是使用永不失败的编码进行解码(解码每个字节,尽管可能解码为无意义的上下文字形),例如“iso-8859-1”。但我相信这对repr 并没有真正的改进;美学上的提升颇有争议,在“完整、明确的信息”方面存在损失的可能性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-07
      • 2010-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-21
      相关资源
      最近更新 更多