TOC

一个编码转换问题

问题

我拿到一串字符串:

"Client: \\344\\275\\240\\345\\245\\275\\357\\274\\214\\344\\270\\226\\347\\225\\214"

根据上下文,我知道这是 UTF-8。

print(b'Client: \344\275\240\345\245\275\357\274\214\344\270\226\347\225\214'.decode())
# 'Client: 你好,世界'

现在的问题是,我怎么把他转换成普通的字符串呢(unicode)?

再举例子

这其实是一个比较普遍的问题,只要有过一段时间 Python 开发,可能就会偶尔碰到这样的问题:

a = "I Love 中国".encode('utf-8')
b = str(a)
# "b'I Love \\xe4\\xb8\\xad\\xe5\\x9b\\xbd'"

由于不同系统或者不同模块之间的衔接有问题(有可能部分组件只支持 ASCII),中间的过程不受我们控制,最后,我们就是拿到了这个 b,怎么给转换成 a?

解决方案

s = "Client: \\344\\275\\240\\345\\245\\275\\357\\274\\214\\344\\270\\226\\347\\225\\214"
result = eval(f'b"{s}".decode("utf-8")')
print(result)
# Client: 你好,世界

但是这有点危险,改成 str.literal_eval 好一些:

s = "Client: \\344\\275\\240\\345\\245\\275\\357\\274\\214\\344\\270\\226\\347\\225\\214"
#  b'Client: \xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c'
import ast
print(ast.literal_eval(f'b"{s}"').decode('utf-8'))

延伸

unicode_escape

In [1]: u'nihao 中国'.encode('raw_unicode_escape')
Out[1]: 'nihao \\u4e2d\\u56fd'

In [2]: u'nihao 中国'.encode('unicode_escape')
Out[2]: 'nihao \\u4e2d\\u56fd'

In [3]: re.sub('.', lambda x: r'\u%04X' % ord(x.group()), 'nihao 中国')
Out[3]: '\\u006E\\u0069\\u0068\\u0061\\u006F\\u0020\\u4E2D\\u56FD'

In [4]: ''.join(r'\u{:04X}'.format(ord(chr)) for chr in 'nihao 中国')
Out[4]: '\\u006E\\u0069\\u0068\\u0061\\u006F\\u0020\\u4E2D\\u56FD'

八进制和十六进制

s = "Client: \\344\\275\\240\\345\\245\\275\\357\\274\\214\\344\\270\\226\\347\\225\\214"
#  b'Client: \xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c'
0o344 == 0xe4 == 228