将Python 3中的字节字符串(`str(utf8_encoded_str)`)转换回Unicode。

12

首先,让我介绍一下问题。

我通过 POST/GET 请求获取了一些数据。该数据是以 UTF-8 编码的字符串。我并不知道这一点,并仅使用了 str() 方法进行转换。现在我拥有了一个完整的“无意义数据”的数据库,找不到回头的方法。

示例代码:

unicode_str - 这是我应该获得的字符串

encoded_str - 这是我通过 POST/GET 请求得到的字符串 - 初始数据

bad_str - 我目前在数据库中拥有的数据,需要从中获取 Unicode。

所以显然我知道如何进行转换: unicode_str =(encode)=> encoded_str =(str)=> bad_str

但我无法想出回头的解决方案: bad_str =(???)=> encoded_str =(decode)=> unicode_str

In [1]: unicode_str = 'Příliš žluťoučký kůň úpěl ďábelské ódy'

In [2]: unicode_str
Out[2]: 'Příliš žluťoučký kůň úpěl ďábelské ódy'

In [3]: encoded_str = unicode_str.encode("UTF-8")

In [4]: encoded_str
Out[4]: b'P\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88 \xc3\xbap\xc4\x9bl \xc4\x8f\xc3\xa1belsk\xc3\xa9 \xc3\xb3dy'

In [5]: bad_str = str(encoded_str)

In [6]: bad_str
Out[6]: "b'P\\xc5\\x99\\xc3\\xadli\\xc5\\xa1 \\xc5\\xbelu\\xc5\\xa5ou\\xc4\\x8dk\\xc3\\xbd k\\xc5\\xaf\\xc5\\x88 \\xc3\\xbap\\xc4\\x9bl \\xc4\\x8f\\xc3\\xa1belsk\\xc3\\xa9 \\xc3\\xb3dy'"

In [7]: new_encoded_str = some_magical_function_here(bad_str) ???
2个回答

14
你将一个字节对象转换为字符串,这只是字节对象的一种表示。你可以使用 ast.literal_eval()(感谢Mark Tolonen提供建议)获取原始的字节对象,然后使用简单的decode()即可完成任务。
>>> import ast
>>> ast.literal_eval(bad_str).decode('utf-8')
'Příliš žluťoučký kůň úpěl ďábelské ódy'

既然是你生成字符串,使用eval()是安全的,但为什么不更加安全呢?


好的,我也考虑了使用eval,但由于我不知道有什么数据以及有很多数据,所以我希望我可以避免这种情况 - 因此没有提到它。但还是谢谢 :) - darkless
4
无论你保存的字符串看起来如何,都无关紧要。只要你按照获取utf-8字符串 -> 将其编码为字节对象 -> 转换为字符串并存储到数据库的过程,你就可以保证这些字符串是无害的字节对象。 - Reti43
没错,我没有意识到每个存储的字符串都是“b'...'”,eval应该将其解释为b'...' :) 感谢您的提醒! - darkless
3
ast.literal_evaleval相比,能够实现相同的功能,但没有安全风险。 - Mark Tolonen
@MarkTolonen 这太棒了。我已经相应地更新了答案。此外,这个函数听起来有点熟悉,如果我以前没有“学习”过它但忘记了,我也不会感到惊讶,因为我从来没有需要它。下次需要更好的记忆! - Reti43
1
@darkless,我想提醒你注意一下,有一个更安全的eval()版本也符合你的要求。 - Reti43

6

请勿使用eval,而应使用:

import codecs
s = 'žluťoučký'
x = str(s.encode('utf-8'))

# strip quotes
x = x[2:-1]

# unescape
x = codecs.escape_decode(x)[0].decode('utf-8')

# profit
x == s

1
感谢提供非评估版本,我需要escape_decode将双斜杠转换为单斜杠。但是我找不到该方法的文档:https://docs.python.org/3.5/library/codecs.html - darkless
哇,这非常好用。 - Franco Gil

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