在处理向mysql插入中文字符的过程中,碰到这样一个问题,明明是utf-8编码的中文str ,但是到了mysql里面显示的并不是中文,而是该中文字符串的utf-8编码的十六进制形式,下面是整个解决过程。

中文字符正常情况下应该是这样的:

>>> a = '中文123'
>>> print(a)
123

但是你如果把一个包含中文的字符放到tuple 里面,却会变成这样:

>>> 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, 我们做个实验:

>>> 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')就可以了。

>>> 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_escapeunicode_escape 都是将转义字符raw 话,将它们当做普通字符来看待,只不过前者只能针对str (编码后的字符)进行操作,后者是针对unicode字符进行操作。

>>> a = u'中文'
>>> a
u'\u4e2d\u6587'
>>> print(a)

>>> b = a.encode('unicode_escape')
'\\u4e2d\\u6587'
>>> print(b)
\u4e2d\u6587

题外话

是时候转Python3了。

参考链接:

python的转义字符

[unicode_escapestring_escape](https://docs.python.org/2/library/codecs.html)