最近在用Python连接SqlServer数据库,从数据库返回的字段出现乱码问题。
乱码形式如下:
'A\x04\x96\xb58\xe8SQ\x9crj,\x91\xe6\x1e\xc1\x16\x00\xae\x13\x90\x81:b|f\xfb\x8b\xe7\x94{\xe6<R\xdau\x897\x95\x15\xd4\xe0\xa6\x04\xf8\x14\x17\x81\xe6"\x94r\x11f\xbfb\x1es\xa8,\xbf#B\xc8X\xee\xac'
数据库中实际存储的内容为:
0x410496B538E853519C726A2C91E61EC11600AE1390813A627C66FB8BE7947BE63C52DA7589379515D4E0A604F8141781E62294721166BF621E73A82CBF2342C858EEAC
在数据库中,查询的字段属性是:varbinary
varbinary是一个变长二进制数据,一般用来存储图片。
第一步、查看数据库编码类型
SELECT COLLATIONPROPERTY('Chinese_PRC_Stroke_CI_AI_KS_WS', 'CodePage')
运行结果为:936
因为:
936 简体中文GBK
950 繁体中文BIG5
437 美国/加拿大英语
932 日文
949 韩文
866 俄文
65001 unicode UFT-8
所以,该数据库编码格式为GBK
2、使用pymssql连接数据库是,设置字符集
由于pymssql不支持GBK等格式,只支持UTF8,所以设置如下:
conn=pymssql.connect(server=server,user=user,password=password,database=db,charset='utf8')
查看pymssql使用文档,发现官方没有给出此参数可接收的实例字符串。进行猜测性调试:
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
//或者
#encoding=utf-8
4、依然乱码无果,所以对照真实记录与乱码,寻找其中的规律。
//乱码
'A\x04\x96\xb58 \x9crj,\x91\xe6\x1e\xc1\x16\x00\xae\x13\x90\x81:b|f\xfb\x8b\xe7\x94{\xe6<R\xdau\x897\x95\x15\xd4\xe0\xa6\x04\xf8\x14\x17\x81\xe6"\x94r\x11f\xbfb\x1es\xa8,\xbf#B\xc8X\xee\xac'
//真实结果
0x410496B538E853519C726A2C91E61EC11600AE1390813A627C66FB8BE7947BE63C52DA7589379515D4E0A604F8141781E62294721166BF621E73A82CBF2342C858EEAC
0x :表示是一个16进制字符串。
真实 乱码
41 A
04 \x04
96 \x96
B538 \b58
E85351 \xe8SQ
………..
对照ASCII码与16进制转换表
16进制 ASCII码
41 A
04 eot
96
b5
38 8
e8
53 S
51 Q
………………
所以,乱码的二进制和实际数据二进制是一致的。但是sql查询返回的结果是把部分16进制转化成ASCII码,没有特殊字符的ASCII码,使用的是原来的16进制。
5、找到原因后,就可以解决问题了,由于乱码是16进制与ASCII码的混合编码,所以需要单独编写一个函数完成解析的功能。
下面附上我写的解析函数,欢迎更优的解决函数:
#encoding=utf-8
class Decode:
"""
功能:解决sql返回结果乱码问题
"""
def MessyCode_To_Hex(self,str):
"""
将乱码解码为数据库中存储的格式
:param str:
:return:
"""
str = repr(str)
TempList = list()
reslist = str.replace('x', '0x').split('\\')
for i in reslist:
if len(i) == 2:
i = hex(ord(i[1]))
TempList.append(i)
elif len(i) == 4:
TempList.append(i)
else:
TempList.append(i[0:4])
for j in range(4, len(i)):
temp = hex(ord(i[j]))
TempList.append(temp)
result = ''
for k in TempList:
result = result + k
result = result.replace('0x', '')
return result[0:len(result)-2]
测试用例与结果:
str2='A\x04\x96\xb58\xe8SQ\x9crj,\x91\xe6\x1e\xc1\x16\x00\xae\x13\x90\x81:b|f\xfb\x8b\xe7\x94{\xe6<R\xdau\x897\x95\x15\xd4\xe0\xa6\x04\xf8\x14\x17\x81\xe6"\x94r\x11f\xbfb\x1es\xa8,\xbf#B\xc8X\xee\xac'
print p.MessyCode_To_Hex(str2)
结果:
410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac
0x410496B538E853519C726A2C91E61EC11600AE1390813A627C66FB8BE7947BE63C52DA7589379515D4E0A604F8141781E62294721166BF621E73A82CBF2342C858EEAC
hhhhhhh,到这里就成功解决乱码问题了,但是实现代码存在优化空间,有兴趣的伙伴可以修改。