如何解码字节(使用ASCII),而不丢失任何“垃圾”字节,如果xmlcharrefreplace和backslashreplace都无效?

5 投票
2 回答
3328 浏览
提问于 2025-04-18 18:10

我有一个网络资源,它应该返回一个按照规范编码的ASCII字符串。但在一些罕见的情况下,我却收到了无用的数据。

比如说,一个资源返回了 b'\xd3PS-90AC',而另一个资源在同样的条件下返回的是 b'PS-90AC'

第一个值里包含了一个非ASCII字符串。这显然违反了规范,但这我无法控制。我们都不确定这到底是无用的数据,还是应该保留的数据。

调用这些远程资源的应用程序会把数据保存在本地数据库里,以便日常使用。我可以简单地用 data.decode('ascii', 'replace') 或者 ..., 'ignore') 来处理,但这样的话,我可能会丢失一些将来可能有用的数据。

我最初的想法是使用 'xmlcharrefreplace''backslashreplace' 作为错误处理方式。这样做的原因是,它们能生成一个可以显示的字符串。但我遇到了一个错误:TypeError: don't know how to handle UnicodeDecodeError in error callback

唯一有效的错误处理方式是 surrogateescape,但这似乎是为文件名设计的。不过,对我来说,这个方法是可行的。

为什么 'xmlcharrefreplace''backslashreplace' 不起作用?我不明白这个错误的原因。

举个例子,预期的执行结果应该是:

>>> data = b'\xd3PS-90AC'
>>> new_data = data.decode('ascii', 'xmlcharrefreplace')
>>> print(repr(new_data))
'&#d3;PS-90AC'

这是一个人为构造的例子。我的目标是不丢失任何数据。如果我使用 ignorereplace 作为错误处理方式,那么相关的字节就会消失,信息就会丢失。

2 个回答

3

为了完整性,我想补充一下,从Python 3.5开始,backslashreplace可以用于解码了,所以你不再需要添加自定义的错误处理器了。

2
>>> data = b'\xd3PS-90AC'
>>> data.decode('ascii', 'surrogateescape')
'\udcd3PS-90AC'

它没有使用 html 实体,但这是一个不错的起点。如果这个不够用,你可能需要自己注册一个错误处理器,具体可以参考 codecs.register_error 的文档。

对于 Python3:

def handler(err):
    start = err.start
    end = err.end
    return ("".join(["&#{0};".format(err.object[i]) for i in range(start,end)]),end)

import codecs
codecs.register_error('xmlcharreffallback', handler)
data = b'\xd3PS-90AC'
data.decode('ascii', 'xmlcharreffallback')

对于 Python 2:

def handler(err):
    start = err.start
    end = err.end
    return (u"".join([u"&#{0};".format(ord(err.object[i])) for i in range(start,end)]),end)

import codecs
codecs.register_error('xmlcharreffallback', handler)
data = b'\xd3PS-90AC'
data.decode('ascii', 'xmlcharreffallback')

两者都会产生:

'ÓPS-90AC'

撰写回答