我该如何解决这个 utf-8 编码错误?

How am I supposed to fix this utf-8 encoding error?

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

La funci\xc3\xb3n est\xc3\xa1ndar datetime. datetime. now() retorna la fecha y hora actual.

此字符串应如下所示:

La función estándar datetime. datetime. now() retorna la fecha y hora actual.

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

>>> 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() 一起使用,这真的很有趣:

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...
}

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

当试图解开一个具有双重编码序列的字符串时,该字符串旨在作为转义序列(即 \ 而不是 \),可以使用特殊的 text encoding codec unicode_escape将它们纠正回预期的实体以进行进一步处理。但是,鉴于输入已经是 str 类型,需要将其转换为 bytes - 假设整个字符串具有完全有效的 ascii 代码点,这可能是用于将初始 str 输入初始转换为 bytes 的编解码器。如果 str 中有标准的 unicode 代码点,则可以使用 utf8 编解码器,因为 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,这个中间字符串可以简单地使用 latin1 编解码器 post 编码为 bytes ] 解码,然后通过 utf8(或任何合适的目标)编解码器将其转回 unicode str 类型:

>>> 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.'

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

>>> 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)