将使用Latin-1字符编码的字节解码为以十进制表示的字符串。

5
我正在进行一个迁移项目,将Web服务器的一层从Python 2.7.8升级到Python 3.6.3,并且在某些特殊情况下遇到了障碍。 当接收到客户端的请求时,负载使用pyzmq在本地传输,而现在在Python 3中,它与str不同,而是以bytes交互。
现在,我接收到的负载是使用iso-8859-1(latin-1)编码方案编码的,我可以很容易地将其转换为字符串,如payload.decode('latin-1'),并将其传递给下一个服务(svc-save-entity),该服务期望字符串参数。
然而,后续服务'svc-save-entity'希望非Latin-1字符(如果存在)以ASCII字符引用的形式表示(例如,对于é,使用é而不是十六进制\xe9)。
我正在努力寻找一种高效的方法来实现这种转换。有没有Python专家可以指导我?基本上,我需要一个名为decode_tostring()的函数的定义:
payload = b'Banco Santander (M\xe9xico)'         #payload is in bytes
payload_str = decode_tostring(payload)           #function to convert into string
payload_str == 'Banco Santander (México)'  #payload_str is a string in ASCII Character Reference

请解释decode_tostring()的定义。:)

1个回答

6
encode()decode()方法接受一个名为errors的参数,允许您指定如何处理在指定编码中无法表示的字符。您要查找的是XML数字字符引用替换,幸运的是,这是codecs模块提供的标准处理程序之一。

现在,实际上按照您想要的方式替换非ASCII字符与其相应的XML数字字符引用有点复杂,因为将非ASCII字符替换为相应的XML数字字符引用的操作发生在编码期间而不是解码期间。毕竟,编码是将字符输入并发出字节的过程,因此仅在编码期间才能告诉您是否具有不属于ASCII的字符。我目前能想到的最干净的方法是解码、重新编码和重新解码,在编码步骤中应用XML实体引用替换。

def decode_tostring(payload):
    return payload.decode('latin-1').encode('ascii', errors='xmlcharrefreplace').decode('ascii')

我不会感到惊讶,如果有一种方法可以在字符串中替换所有非ASCII字符为XML数字字符引用,并将其返回给您。如果有这样的方法,您可以使用它来替换编码和第二次解码。但是我不知道是否有这样的方法。目前我找到的最接近的方法是xml.sax.saxutils.escape(),但它只作用于特定的字符。
这段内容与您的主要问题并不相关,但我想澄清一件事情:像 数字实体(如 é 这样的东西是 SGML、HTML 和 XML 的特性,它们是标记语言——一种将结构化数据表示为文本的方式。它们与 ASCII 没有任何关系。像 ASCII 这样的字符编码只是一张表格,其中包含了一些字符和一些字节序列,使得表格中的每个字符都被映射到表格中的一个字节序列,反之亦然,并添加了一些约束条件以使映射无歧义。
如果您有一个包含特定编码表中不存在字符的字符串,则无法使用该编码对该字符串进行编码。但是您可以通过将编码表中不存在的字符替换为编码表中存在的字符序列并将新字符串进行编码来将该字符串转换为新字符串。有许多方法可以进行替换,其中 XML 数字实体引用只是其中一个示例。Python 的 codecs 模块中的其他一些错误处理程序代表了其他处理此替换的方法。

非常感谢@David Z提供的意见,这些信息对我非常有帮助。我会继续寻找一种替代方法,以避免额外的编码和解码步骤。但与此同时,考虑到在我的情况下这些Latin-1字符的存在是罕见的,并且Latin-1字母表代码从192开始,我可以在我的函数中放置一个检查 - if any(char >= 192 for char in list(payload)): return payload.decode('latin-1').encode('ascii', errors='xmlcharrefreplace').decode('ascii') else: return payload.decode('latin-1') - Achin Saxena
以上内容应该能够帮助我在大多数情况下避免额外的编码/解码。另外,针对您的第二个输入,在保存实体之前会发送通知,这取决于配置,可以是Python字典形式或XML格式。当以XML格式发送时,一切都很好,但当以Python字典格式发送时,如果遇到任何十六进制形式的Latin-1字符(例如\xe9),后续服务将无法处理它。也许需要在那一端进行改进,这可能是我接下来要做的任务 :) - Achin Saxena

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接