Python中UTF-8与unicode_escape双向转换时字符失真的问题及原字符串恢复方法咨询
Python中UTF-8与unicode_escape双向转换时字符失真的问题及原字符串恢复方法咨询
先来看你碰到的具体问题:你运行了这段代码后,输出结果和预期不符,还搞不懂为啥可逆操作混在一起就失效了,对吧?
你的代码:
s = "Hello隼" s = s.encode("utf-8").decode("unicode_escape").encode("unicode_escape").decode("utf-8") print(s)
输出是 Hello\\xe9\\x9a\\xbc,你说你知道这些转义字符对应那个汉字,但终端、URL这类场景里必须显示原符号,而且你本来以为编码解码操作是可逆的,单独用UTF-8或者unicode_escape都没问题,混在一起就出岔子了,想知道怎么把原字符串找回来。
先搞懂为啥会出问题:一步步拆解你的代码执行流程
咱们把每一步的变化拆解开,就能明白哪里踩坑了:
- 初始字符串
s = "Hello隼":这里的“隼”在Python里是Unicode字符,对应的UTF-8字节是b'\xe9\x9a\xbc'。 s.encode("utf-8"):把Unicode字符串转成UTF-8字节串,得到b'Hello\xe9\x9a\xbc'。- 关键错误:
.decode("unicode_escape")——unicode_escape解码是把字节串当作unicode_escape编码的内容来解析,但你这里的字节串是UTF-8格式的啊!\xe9这类字节在unicode_escape规则里会被解析成单独的Unicode字符,比如\xe9变成é,\x9a变成不可见的控制字符,\xbc变成¼,所以这一步后字符串变成了Helloé\x9a¼。 .encode("unicode_escape"):把这个变了样的字符串转成unicode_escape编码的字节串,每个特殊字符都会被转义,比如é变成b'\\xe9',最终得到b'Hello\\xe9\\x9a\\xbc'。.decode("utf-8"):把这个字节串转成Unicode字符串,就得到了你看到的Hello\\xe9\\x9a\\xbc。
说白了,你把UTF-8编码的字节串错误地用unicode_escape去解码,这一步直接破坏了原字符的结构,后续操作自然没法还原回去了。
怎么恢复原字符串?
如果现在你手里只有那个失真的字符串 Hello\\xe9\\x9a\\xbc,可以用下面的代码还原:
s_broken = "Hello\\xe9\\x9a\\xbc" # 逆向操作,注意用latin-1做中间转换 s_original = s_broken.encode("utf-8").decode("unicode_escape").encode("latin-1").decode("utf-8") print(s_original) # 输出:Hello隼
拆解下恢复逻辑:
s_broken.encode("utf-8"):得到字节串b'Hello\\xe9\\x9a\\xbc'。.decode("unicode_escape"):还原到之前出错的中间字符串Helloé\x9a¼。.encode("latin-1"):latin-1是单字节编码,每个Unicode字符对应一个字节,刚好把é转回b'\xe9',\x9a转回b'\x9a',¼转回b'\xbc',还原成最初的UTF-8字节串b'Hello\xe9\x9a\xbc'。.decode("utf-8"):把UTF-8字节串解码回原Unicode字符串Hello隼。
额外提醒:正确的可逆转换姿势
如果你只是想做Unicode和unicode_escape格式的互转,直接用下面的方式就好,别乱混UTF-8:
- 转成unicode_escape格式字符串:
s.encode("unicode_escape").decode("utf-8") - 从unicode_escape格式还原:
s_escaped.encode("utf-8").decode("unicode_escape")
如果是处理UTF-8和Unicode的转换,直接用 s.encode("utf-8") 和 b_str.decode("utf-8") 就足够了,只有在明确需要处理转义字符的时候再用unicode_escape。
备注:内容来源于stack exchange,提问作者Some Guy
相关产品推荐
相关产品推荐

