首页 > 解决方案 > 我应该如何解决这个 utf-8 编码错误?

问题描述

所以,我有像这样的非二进制字符串,它的编码被破坏了:

La funci\xc3\xb3n est\xc3\xa1ndar 日期时间。约会时间。now() retorna la fecha y hora 实际。

该字符串应如下所示:

La función estándar 日期时间。约会时间。now() retorna la fecha y hora 实际。

在交互式控制台中,很容易修复:就像这样:

>>> b'La funci\xc3\xb3n est\xc3\xa1ndar datetime. datetime. now() retorna la fecha y hora actual.'.decode('utf-8')

这将输出正确解码的字符串。但是,在我尝试构建的脚本中,这个字符串就像您在第一个示例中看到的一样,但是是 unicode,而不是二进制。

我已经尝试了所有我能想到的技巧(除了硬编码一个等价字典并使用它replace(),如果我能帮助它,我宁愿不这样做):我试过的最疯狂的事情是:

# Just to clarify the format of the broken strings, I declare this one here
broken_string = 'La funci\\xc3\\xb3n est\\xc3\\xa1ndar datetime. datetime. now() retorna la fecha y hora actual.'

match = re.findall(r'\\x[a-z0-9][a-z0-9]', broken_string)
for e in match:
    broken_string = str(broken_string.encode().replace( e.encode(), str(chr(int(e[-2:], 16))).encode() ))

好吧,实际上这个循环最终把字符串弄得更糟:-$

这个可怕的火车残骸只是我能向你展示的最疯狂的想法。实际上,我已经尝试了很多东西,以至于我都不记得它们了。但你可能会在这里看到我的意图。

实际上很有趣,我似乎无法以一种优雅的方式解决这个问题,而不必硬编码这种风格的字典以便 str.replace()在循环中使用 with:

dict_for_fix = {
    '\\xc3\\xb3' : b'\xc3\xb3'.decode('utf-8'),
    # I mean, I would have to brute-force hardcode lots of combinations this way...
}

这简直让我大吃一惊。难道没有比这更优雅的解决方案了吗?

标签: pythonpython-3.xcharacter-encodingpython-3.6

解决方案


当试图解开具有双重编码序列的字符串时,该字符串旨在成为转义序列(即\\代替\),特殊的文本编码编解码器unicode_escape可用于将它们纠正回预期的实体以进行进一步处理。但是,鉴于输入已经是 类型str,它需要转换为bytes- 假设整个字符串具有完全有效的ascii代码点,这可能是用于将初始str输入初始转换为 的编解码器bytes。如果utf8在 中表示标准 unicode 代码点,则可以使用编解码器str,因为unicode_escape序列不会影响这些代码点。例子:

>>> broken_string = 'La funci\\xc3\\xb3n est\\xc3\\xa1ndar datetime.'
>>> broken_string2 = 'La funci\\xc3\\xb3n estándar datetime.'
>>> broken_string.encode('ascii').decode('unicode_escape')
'La función estándar datetime.'
>>> broken_string2.encode('utf8').decode('unicode_escape')
'La función estándar datetime.'

假设unicode_escape编解码器假定解码为latin1,则此中间字符串可以简单地bytes使用编解码器后解码进行编码,然后通过(或任何适当的目标)编解码器latin1将其转换回 unicodestr类型:utf8

>>> broken_string.encode('ascii').decode('unicode_escape').encode('latin1').decode('utf8')
'La función estándar datetime.'
>>> broken_string2.encode('utf8').decode('unicode_escape').encode('latin1').decode('utf8')
'La función estándar datetime.'

根据要求,一个附录来澄清部分混乱的字符串。请注意,由于存在未转义字符,尝试broken_string2使用编解码器进行ascii解码将不起作用。á

>>> broken_string2.encode('ascii').decode('unicode_escape').encode('latin1').decode('utf8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character '\xe1' in position 21: ordinal not in range(128)

推荐阅读