pymssql读取varchar字段中文显示乱码的问题分析
问题
用python的pymssql模块读取旧业务系统后台SQL Server 2000数据库展示数据为乱码
开发环境
- 操作系统:windows 8
- 数据库 MS SQL Server 2000,默认配置
- python 2.7.6
- pymssql 2.1.1
- 开发工具:PyCharm 4.0
业务逻辑
数据库的[rooms]表记录一些功能房间列表,与其他接口数据进行对比,然后输出对比结果。
rooms表结构:
CREATE TABLE [rooms] (
[id] [int] IDENTITY (1, 1) NOT NULL ,
[name] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
PRIMARY KEY CLUSTERED ([id] ON [PRIMARY] ,
UNIQUE NONCLUSTERED ([des]) ON [PRIMARY]
) ON [PRIMARY]
GO
模拟代码
# -*- coding: utf-8 -*-
import pymssql rooms=None
with pymssql.connect(host='192.168.1.100',database='builds',
user='sa',password='password',
# charset='utf8',
) as conn:
cur=conn.cursor()
sql="select id,name from rooms"
cur.execute(sql)
rooms=cur.fetchall()
if rooms and isinstance(rooms,(list,tuple)):
for room_id,room_name in rooms:
print "\t".join([str(room_id),room_name])
在通用环境中运行代码,room_name变量列显示乱码
问题分析
- 调整连接字符集
首先想到的解决办法是,指定pymssql.connect参数charset的字符集值,使得内外数据编码一致。
依据,“默认情况下,SQL Server 2000使用ISO字符集(代码页1252)。这个字符集也叫ISO-8859-1 Latin1 或者ANSI字符集。它和Windows9x及Windows NT/2000操作系统相兼容,提供了与大多数语言最大兼容性。SQL Server2000中还包含代码页936(简体中文),该字符集包含对简体中文支持的字符”,将charset设置为gbk或cp936,更为合适。查看pymssql使用文档,发现官方没有给出此参数可接收的实例字符串。进行猜测性调试:
<charset='gbk'>运行抛出异常:pymssql.OperationalError: (20017, 'DB-Lib error message 20017, severity 9:\nUnexpected EOF from the server\nDB-Lib error message 20002, severity 9:\nAdaptive Server connection failed\n')
<charset='cp936'>调试模式下pymsql.connect无异常信息,但程序直接退出
<charset='utf8'>运行正常,输出依然乱码;不指定此参数值时,程序使用默认值'UTF-8'
结论:此路不通 - 特定字符串调试
使用PyCharm调试程序,选定特定room_name值,来进行分析# 注意此时输出标记为u,说明识别为unicode编码,正常时此时print出是真实值
>>> room_name
u'\xbf\xec\xb5\xdd\xbc\xe4\xa3\xa8\xc3\xc5\xc4\xda\xa3\xa9'
# 打印原始值为乱码,所以怀疑实际存储的是被标记为unicode的其他编码
>>> print room_name
¿ìµÝ¼ä£¨ÃÅÄÚ£©
# 这时可以将引号内赋值,再使用chardet.detect()判断
>>> aa='\xbf\xec\xb5\xdd\xbc\xe4\xa3\xa8\xc3\xc5\xc4\xda\xa3\xa9'
>>> aa
'\xbf\xec\xb5\xdd\xbc\xe4\xa3\xa8\xc3\xc5\xc4\xda\xa3\xa9'
# 果然,检测出的结果是GB2312编码
>>> chardet.detect(aa)
{'confidence': 0.99, 'encoding': 'GB2312'}
# 输出正常
>>> print aa.decode('gb2312')
快递间(门内)
# 此时,需要unicode->encode('Latin1')->decode('GB2312')
>>> room_name.encode('latin1').decode('GB2312')
u'\u5feb\u9012\u95f4\uff08\u95e8\u5185\uff09'
>>> print room_name.encode('latin1').decode('GB2312')
快递间(门内)
解决办法
pymssql基础实现使用的是cpython,从GitHub的官方代码文件_mssql.pyx,可以看到一些处理过程。使用strcpy函数对数据交换,因为对cpython不了解,怀疑是在处理双字节文字转码时的一点bug。
这个问题有两个解决办法:
- 代码中显式转码
方法:unicode变量.encode('latin1').decode('gbk'),详细情况可以参考下方的“PYTHON-进阶-编码处理小结”
一般情况下对unicode编码不做encode处理,但必要时可以encode为Latin1,实现脱unicode操作,然后再以合适字符集decode为正确unicodeprint "\t".join([str(room_id),room_name.encode('latin1').decode('gbk')])
- 字符定义使用NVARCHAR
这种方式在存储和读取时都使用unicode编码,和python运转字节码一致,可以很好避免此类问题。当然数据库存储空间要牺牲一些。[room_name] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL
原文:这里
参考:
1)"UnicodeDecodeError: ‘gbk’ codec can’t decode bytes in position 2-3: illegal multibyte sequence"
2)水木社区:用pymssql的时候出现了很诡异的字符集问题
pymssql读取varchar字段中文显示乱码的问题分析的更多相关文章
- c# 关于抓取网页源码后中文显示乱码的原因分析和解决方法
原因分析:首先,目前大多数网站为了提升网页浏览传输速率都会对网站内容在传输前进行压缩,最常用的是GZIP压缩解压解压算法,也是支持最广的一种. 因为网站传输时采用的是GZIP压缩传输,如果我们接受we ...
- C#.NET ORM FreeSql 读取使用 US7ASCII 的 Oracle 数据库中文显示乱码问题
前言 关于 Oracle US7ASCII 中文乱码的问题,Ado.Net 和 Odbc 无法解决.包括最新的.Net Core..NET6..NET7 都无法解决这个问题. FreeSql 对 Or ...
- MySQL 中文显示乱码以及中文查询条件返回0条结果的问题解决
最近关于中文显示乱码的贴子比较多,所以也做了个总结: 可以参考一下杨涛涛版主的<各种乱码问题汇总>http://topic.csdn.net/u/20071124/08/3b7eae6 ...
- MySQL 中文显示乱码
最近关于中文显示乱码的贴子比较多,所以也做了个总结: 可以参考一下杨涛涛版主的<各种乱码问题汇总> http://topic.csdn.net/u/20071124/08/3b7eae69 ...
- SecureCRT中文显示乱码
环境:SecureCRT登陆REDHAT5.3 LINUX系统 问题:vi编辑器编辑文件时文件中的内容中文显示乱码,但是直接使用linux系统terminal打开此文件时中文显示正常,确诊问题出现在客 ...
- Linux中文显示乱码?如何设置centos显示中文
Linux中文显示乱码?如何设置centos显示中文 怎么设置Linux系统中文语言,这是很多小伙伴在开始使用Linux的时候,都会遇到一个问题,就是终端输入命令回显的时候中文显示乱码.出现这个情况一 ...
- Xshell个性化设置,解决Xshell遇到中文显示乱码的问题
在同事的推荐下,今天开始使用Xshell连接Linux,但是发现一个“遇到中文显示乱码”的问题, 同事的解决方案如下: 平常给Linux上传文件之前,先把文件转换成UTF-8编码形式, 然后设置Xsh ...
- (转)sqlplus中文显示乱码的问题
sqlplus中文显示乱码的问题 2010-07-19 11:33:26 分类: LINUX 在windows下sqlplus完全正常,可是到linux下,sqlplus中文显示就出问题了,总是显示“ ...
- GB2312、GBK和UTF-8三种编码以及QT中文显示乱码问题
1.GB2312.GBK和UTF-8三种编码的简要说明 GB2312.GBK和UTF-8都是一种字符编码,除此之外,还有好多字符编码.只是对于我们中国人的应用来说,用这三种编码 比较多.简单的说一下, ...
随机推荐
- iinflux数据库使用
特殊用法: http://blog.fatedier.com/2016/07/05/research-of-time-series-database-influxdb/ 创建表及表中的key和valu ...
- Qt5官方demo解析集30——Extending QML - Binding Example
本系列全部文章能够在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集29--Extendin ...
- 手游产品经理初探(八)CasinoStar玩家离开原因分析
通过Delta DNA分析报告.综合我们的游戏进行思考,我总结了几条玩家流失的经验: 1.在有限的前60秒我们没有花足够的精力去吸引玩家.就是说我们要花大量的经历在玩家进入游戏的60秒的体验上(我的澳 ...
- 使用azure send grid发送email
1. create a send grid account 2. remember the username/password of the send grid account watermark/2 ...
- [Other]来做一个微信打印机吧 -- 微信打印的设计思路參考
项目源代码地址:https://github.com/callmewhy/why-wechat-printer 近期微信打印机小火了一把.比方印美团.747微信打印机,都是利用微信公共平台实现照片的打 ...
- [leetcode解题记录]Jump Game和Jump Game II
Jump Game Given an array of non-negative integers, you are initially positioned at the first index o ...
- 各种加载效果,适合做加载loading动画效果 Eclipse版
Animation.rar 链接: http://pan.baidu.com/s/1c0QkOz2 密码: kd57
- ShopMall
https://github.com/KingsleyYau/ShopMall-Android https://github.com/KingsleyYau/ShopMall-iOS https:// ...
- mysql insert操作
insert的语法 INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [(col_name,...)] ...
- 项目Beta冲刺(团队1/7)
项目Beta冲刺(团队1/7) 团队名称: 云打印 作业要求: 项目Beta冲刺(团队) 作业目标: 完成项目Beta版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 陈宇 ...