如何解码字节(使用ASCII),而不丢失任何“垃圾”字节,如果xmlcharrefreplace和backslashreplace都无效?
我有一个网络资源,它应该返回一个按照规范编码的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'
这是一个人为构造的例子。我的目标是不丢失任何数据。如果我使用 ignore
或 replace
作为错误处理方式,那么相关的字节就会消失,信息就会丢失。
2 个回答
为了完整性,我想补充一下,从Python 3.5开始,backslashreplace
可以用于解码了,所以你不再需要添加自定义的错误处理器了。
>>> 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'