在处理向mysql插入中文字符的过程中,碰到这样一个问题,明明是utf-8编码的中文str ,但是到了mysql里面显示的并不是中文,而是该中文字符串的utf-8编码的十六进制形式,下面是整个解决过程。
中文字符正常情况下应该是这样的:
1 2 3 |
>>> a = '中文123' >>> print(a) 中文123 |
但是你如果把一个包含中文的字符放到tuple 里面,却会变成这样:
1 2 3 |
>>> a = tuple(['中文123', 'hello']) >>> print(a)('\xe4\xb8\xad\xe6\x96\x87123', 'hello') # 这里按理说应该显示的是('中文123', 'hello') |
中文字符显示成了编码后的十六进制形式,也就是说,\x 这个python的保留字符(用来表示它后面两个字符是十六进制值),并没有得到“正确的”解析,实际上这里是把’\xe4\xb8\xad\xe6\x96\x87′ 当成一个raw strings 来处理,这里面的\x 没有任何特别的意思,就是字面的\x ,所有它后面十六进制数也都只是表面上的意思。
为什么会这样?
tuple 应该是对它里面的str 做了一个encode(‘string_escape’) 的操作,这个操作同r”等价,意思是生成一个raw strings,官方的解释是Produce a string that is suitable as string literal in Python source code, 我们做个实验:
1 2 3 4 5 6 7 8 9 10 11 |
>>> a = '中文123' >>> a '\xe4\xb8\xad\xe6\x96\x87123' >>> print(a) 中文123 >>> b = a.encode('string_escape') >>> b '\\xe4\\xb8\\xad\\xe6\\x96\\x87123' >>> print(b) \xe4\xb8\xad\xe6\x96\x87123 |
嗯,一切都清楚了,那么问题来了,tuple 为啥要这么干呢…暂时不知道…
解决办法
对字符做decode(‘string_escape’)就可以了。
1 2 3 |
>>> c = b.decode('string_escape') >>> print(c) 中文123 |
总结
首先,tuple 会它里面的中文字符做一个r” 的转换,这是个坑,踩过了就不说了。
其次,知道了r”的函数写法是这样的: encode(‘string_escape’) ,也就是说,从此以后,可以对一个变量进行r” 操作啦。
拓展
其实还有一个unicode_escape 的编码方式,官方的解释是Produce a string that is suitable as Unicode literal in Python source code.也就是说,将\u 这个保留字符按照字面意思去解释,也就是raw unicode话。
string_escape 和unicode_escape 都是将转义字符raw 话,将它们当做普通字符来看待,只不过前者只能针对str (编码后的字符)进行操作,后者是针对unicode字符进行操作。
1 2 3 4 5 6 7 8 9 10 |
>>> a = u'中文' >>> a u'\u4e2d\u6587' >>> print(a) 中文 >>> b = a.encode('unicode_escape') b '\\u4e2d\\u6587' >>> print(b) \u4e2d\u6587 |