数据库varbinary字符串乱码问题

最近在用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,到这里就成功解决乱码问题了,但是实现代码存在优化空间,有兴趣的伙伴可以修改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值