【问题标题】:How should I decode bytes (using ASCII) without losing any "junk" bytes if xmlcharrefreplace and backslashreplace don't work?如果 xmlcharrefreplace 和 backslashreplace 不起作用,我应该如何解码字节(使用 ASCII)而不丢失任何“垃圾”字节?
【发布时间】:2014-08-22 08:43:51
【问题描述】:

我有一个网络资源,它返回的数据应该(根据规范)是一个 ASCII 编码的字符串。但在极少数情况下,我会收到垃圾数据。

例如,一个资源返回b'\xd3PS-90AC',而另一个资源,对于相同的键返回b'PS-90AC'

第一个值包含一个非 ASCII 字符串。显然违反了规范,但不幸的是我无法控制。我们没有人能 100% 确定这真的是垃圾或应该保留的数据。

调用远程资源的应用程序将数据保存在本地数据库中以供日常使用。我可以简单地做一个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 错误处理程序,则相关字节基本上会消失,并且信息会丢失。

【问题讨论】:

  • 我不清楚预期的“输出”是什么。你想要“ASCII”字符串“垃圾”字节一起(比如u'\u00d3PS-90AC')?或者类似于data.decode('unicode_escape') 的结果?
  • 我添加了一些示例执行。并不是说示例输出有点出自我的脑海。如果它使用不同的语法,那没关系。
  • 我添加了标签 Python3,因为您的示例暗示了这一点。还是我错了?
  • 没关系 ;) 因为 surrogateescapebackslashreplace 仅存在于 Python3 中。目前我正在编写的库仍在由 one Python 2 应用程序使用,因此首选 Python2 解决方案,但我们计划最终将剩下的一个应用程序移植到 Python3。所以没关系...最坏的情况,我们必须现在移植它 :)

标签: python python-3.x encoding byte


【解决方案1】:

为了完整起见,想从 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'
    

    【讨论】:

    • 我一直在阅读这个话题。而且我不确定我最初使用xmlcharrefreplace 的想法是否是个好主意。引用的值指向“Unicode 代码点”。通过查找211,我找到了ȑ(utf-8 字节值c8 91)。所以我不确定你将如何从211 回到\xd3。而且我认为使用surrogateescape 可能不那么模棱两可...:\
    • 也许我们过于关注“如何”,而没有真正知道您要做什么。是不是该问另一个问题了:)?
    • @exhuma BTW 211(10) 是 d3(16)。这只不过是一个简单的 dec->hex 转换。话虽如此,我个人会推动使用 Unicode 代码点。但是一旦 angin 没有澄清你对那个“瘾君子字符串”的使用,就很难说。
    • 你是对的。我想过去两天我对字节的关注太多了。我可能应该休息一下。
    猜你喜欢
    • 1970-01-01
    • 2011-02-28
    • 2018-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多