数据库乱码问题 & Python 编码问题(Unicode 的 encode、decode 相互转换 )
2012-11-01 14:59
761 查看
前言:
今天有个项目需要合并(A合并到B),我所做的就是数据库的合并操作,其中出现的主要问题就是乱码的问题。乱码这个问题是很常见的问题,今天整理了下自己所理解的一点见解。
案例:
查看表的时候都是乱码,根本不能进行合并。当时就认为肯定是自己查看时候的字符集不对,试了“set names = gbk、utf8、latin1”,均显示乱码。再怀疑是不是表结构的问题(根本不可能啊,项目都跑了好几年了),不过表的编码确实的用charset latin1 来建立的。而用lantin1 建立表,在数据库层写入数据(中文)的话,肯定会报warning,不会存成功的而且存的都是?符号,但上面的结果却有� 符号,所以是显示的问题,其实是正常的。经过排查确定是自己终端编码显示的问题,改成GBK,并且做默认的字符集连接下才能正常显示(latin1:set names latin1),因为当时存数据就是做latin1的下面写入的。上面说明表中的文字是GBK编码。
注意:latin1可以存储任何东西,包括汉字,二进制等。latin1是单字节的,存储都会用内部的编码去表示。只要输入流和输出流一致(怎么存就怎么取) 就不会出现乱码情况。如:
表的编码是UTF8 ,那么在进入数据库后,需要在utf8的字符集下才能正常(set names utf8)
表的编码是GBK ,那么在进入数据库后,需要在gbk的字符集下才能正常(set names gbk)
首先看到表的字符集编码是什么,才能相应的set names。要是输入结果像上面显示的这样,就和终端的编码有关系了,需要自己设置下。
如何让表字符编码变成gbk呢?单单的alter 转换是不行的。之后就尝试用python来读取插入表。
看看latin1编码如何存汉字:(Python)
上面的信息说明:latin1确实可以存中文。(在set names latin1下面读的)
<脚本>向latin1编码的表中插入数据,执行脚本,第一次显示乱码,第二次显示正常,他们的区别是 输出流是gbk,而 系统默认/终端默认 的是utf8,所以出现不同的结果。(第二次把 系统默认/终端默认 编码改成了gbk)
<数据表> 表的编码是latin1,并且当时的字符集是latin1(set names latin1,要和表编码一致)。第一次显示乱码,第二次显示正常,他们的区别是 输出流是gbk,而 系统默认/终端默认 的是utf8,所以出现不同的结果。(第二次把 系统默认/终端默认 编码改成了gbk)
其实也可以把latin1存储汉字的表备份出来,文件中要是最新字符集都是有效的,可以用vi可以直接编辑查看。要是出现无效的编码则也可以用: iconv 来转码之后再还原。
当然,还原之后也是latin1 字符集下查看的。
解析:
1,Mysql数据库乱码:这个可以做网上搜到很多信息,就不细说了。只要知道怎么存就怎么取。(有时候set names utf8并且终端也是utf8 可以直接对gbk编码的表进行读取)
2,Python 编码问题,涉及到Unicode 的 encode、decode 相互转换 。(可能做执行中出:“UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)” 的错误信息。)
知识点:
decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串转换成unicode编码。
encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode('gb2312'),表示将unicode编码的字符串转换成gb2312编码。
字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。
测试:
系统默认编码是UTF8,生成一个文件,用GBK编码生成中文。
从上面的信息得到:当读出文本时候还是乱码,因为cat 默认就是按照文本的编码读出,python中的read也是一样。但做python中默认的是unicode编码。按照知识点理的说明需要转换成为unicode才能正常显示。最后还需要把unicode转换成系统默认的文件才行。验证:
所以存到文件最后以系统默认的编码存才能存的进去。
open 按照固定字符集打开:
一个函数:isinstance()
回归:
了解了这些之后,那对数据库表的导出脚本:conn.character_set_name() 是显示数据库的链接字符集,可以print出来,例子理显示为lanti1
结果:
转换:latin1 表转换到 gbk编码的表:原来表本身就存在乱码(不可逆),错误了继续执行:
因此,对于数据库方面来讲,遇到乱码时,先要核对set names里的三个参数是什么,再看终端使用什么编码。 都一致的话大部分的情况不会乱码,不能随便用alter table convert to 进行转码,转码的时候一定要先搞明白,字符串str是什么编码(程序转换字符存表的的时候使用的是什么),然后通过脚本(python 中 先把 decode成unicode,然后再encode成其他编码)进行解码,编码。
关于python 的encode与decode 下面有更多信息:
http://cenalulu.github.io/mysql/mysql-mojibake 值得一看
http://blog.csdn.net/lf8289/article/details/2465196
http://blog.csdn.net/lxdcyh/article/details/4018054
http://www.cnblogs.com/evening/archive/2012/04/19/2457440.html
关于MySQL乱码: http://blog.csdn.net/yah99_wolf/article/details/7391089
今天有个项目需要合并(A合并到B),我所做的就是数据库的合并操作,其中出现的主要问题就是乱码的问题。乱码这个问题是很常见的问题,今天整理了下自己所理解的一点见解。
案例:
NAME | COMPANY | RNAME |
A | the Feed Institute, CAAS | tiezhengyuan |
B | ??����????????????????????????????��??��???�� | ?????? |
C | ����?????????��?��???????????? | ?????�� |
D | AB | ?????? |
E | ?????????????��?????????????????? | ?????? |
F | ???��???????��???��???????�� | ?????? |
G | ?????��302?????��?��???????????? | ?��?? |
H | ???????��?��?????????????? | ?????�� |
I | ???????????�� | ?????? |
注意:latin1可以存储任何东西,包括汉字,二进制等。latin1是单字节的,存储都会用内部的编码去表示。只要输入流和输出流一致(怎么存就怎么取) 就不会出现乱码情况。如:
表的编码是UTF8 ,那么在进入数据库后,需要在utf8的字符集下才能正常(set names utf8)
表的编码是GBK ,那么在进入数据库后,需要在gbk的字符集下才能正常(set names gbk)
首先看到表的字符集编码是什么,才能相应的set names。要是输入结果像上面显示的这样,就和终端的编码有关系了,需要自己设置下。
如何让表字符编码变成gbk呢?单单的alter 转换是不行的。之后就尝试用python来读取插入表。
看看latin1编码如何存汉字:(Python)
#!/usr/bin/python #encoding: utf-8 #------------------------------------------------------------------------------- # Name: latin_to_gbk_bak.py # Purpose: gbk 编码存到 latin1编码 # Author: zhoujy # Created: 2012-10-31 # update: 2012-10-31 #------------------------------------------------------------------------------- import MySQLdb a=u'zhoujy' b=u'中国' /*生成unicode */ c=u'周金义' conn = MySQLdb.connect(host='localhost',user='root',passwd='123456',db='test') cursor = conn.cursor() /*编码成gbk存到latin1 的表中*/ query = "insert into users_latin(username,user_company,user_realname) values('%s','%s','%s')" %(a.encode('gbk'),b.encode('gbk'),c.encode('gbk')) cursor.execute(query) conn.commit() print query
root@localhost : test 10:55:10>CREATE TABLE `users_latin` ( -> `username` varchar(25) NOT NULL DEFAULT '', -> `user_realname` varchar(50) NOT NULL DEFAULT '', -> `user_company` varchar(100) NOT NULL DEFAULT '' -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; Query OK, 0 rows affected (0.07 sec)
zhoujy@zhoujy:~$ python latin_to_gbk_bak.py 1 insert into users_latin(username,user_company,user_realname) values('zhoujy','�й�','�ܽ���') zhoujy@zhoujy:~$ python latin_to_gbk_bak.py 2 insert into users_latin(username,user_company,user_realname) values('zhoujy','中国','周金义') root@localhost : test 10:55:14>select * from users_latin; 1 +----------+---------------+--------------+ | username | user_realname | user_company | +----------+---------------+--------------+ | zhoujy | �ܽ��� | �й� | +----------+---------------+--------------+ 1 row in set (0.00 sec) root@localhost : test 10:56:06>select * from users_latin; 2 +----------+---------------+--------------+ | username | user_realname | user_company | +----------+---------------+--------------+ | zhoujy | 周金义 | 中国 | +----------+---------------+--------------+ 1 row in set (0.00 sec)
上面的信息说明:latin1确实可以存中文。(在set names latin1下面读的)
<脚本>向latin1编码的表中插入数据,执行脚本,第一次显示乱码,第二次显示正常,他们的区别是 输出流是gbk,而 系统默认/终端默认 的是utf8,所以出现不同的结果。(第二次把 系统默认/终端默认 编码改成了gbk)
<数据表> 表的编码是latin1,并且当时的字符集是latin1(set names latin1,要和表编码一致)。第一次显示乱码,第二次显示正常,他们的区别是 输出流是gbk,而 系统默认/终端默认 的是utf8,所以出现不同的结果。(第二次把 系统默认/终端默认 编码改成了gbk)
其实也可以把latin1存储汉字的表备份出来,文件中要是最新字符集都是有效的,可以用vi可以直接编辑查看。要是出现无效的编码则也可以用: iconv 来转码之后再还原。
cat users.sql | iconv -c -f gbk > users_qq.sql
当然,还原之后也是latin1 字符集下查看的。
解析:
1,Mysql数据库乱码:这个可以做网上搜到很多信息,就不细说了。只要知道怎么存就怎么取。(有时候set names utf8并且终端也是utf8 可以直接对gbk编码的表进行读取)
2,Python 编码问题,涉及到Unicode 的 encode、decode 相互转换 。(可能做执行中出:“UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)” 的错误信息。)
知识点:
decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串转换成unicode编码。
encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode('gb2312'),表示将unicode编码的字符串转换成gb2312编码。
字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。
测试:
系统默认编码是UTF8,生成一个文件,用GBK编码生成中文。
zhoujy@zhoujy:~$ cat gbk.txt �ܽ�� >>> f=open('gbk.txt') >>> d=f.read() >>> print d �ܽ�� >>> print d.decode('gbk') #转换成了unicode 周金义 >>> print d.decode('gbk').encode('utf8') 周金义
从上面的信息得到:当读出文本时候还是乱码,因为cat 默认就是按照文本的编码读出,python中的read也是一样。但做python中默认的是unicode编码。按照知识点理的说明需要转换成为unicode才能正常显示。最后还需要把unicode转换成系统默认的文件才行。验证:
>>> f=open('gbk.txt') >>> a=f.read() >>> gbk=a.decode('gbk') /* 将gbk编码的字符串转换成unicode编码*/ >>> gbk u'\u5468\u91d1\u4e49\n' /*u开头的unicode编码*/ >>> print gbk 周金义 /*python里面正常显示,因为默认就是unicode编码*/ >>> f=open('gbk.txt','w') >>> f.write(gbk) /*写文件*/ Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128) /*字符集的问题报错*/ >>> utf=a.decode('gbk').encode('utf8') /* 将gbk编码的字符串转换成unicode编码*,再转换成utf8格式,unicode当成中间编码*/ >>> utf '\xe5\x91\xa8\xe9\x87\x91\xe4\xb9\x89\n' /*utf8编码显示*/ >>> print utf 周金义 >>> f=open('gbk.txt','w') >>> f.write(utf) /*写文件*/ >>> zhoujy@zhoujy:~$ cat gbk.txt /*和第上面的比下,看到正常的文字,这是控制台信息输出窗口按照ascii编码输出utf8编码的字符串的结果。*/ 周金义
所以存到文件最后以系统默认的编码存才能存的进去。
open 按照固定字符集打开:
>>> import codecs >>> f=codecs.open('gbk.txt',encoding='gbk') >>> x=f.read() >>> x /* 节省了 decode的步骤 */ u'\u5468\u91d1\u4e49\n' >>> x.encode('utf8') '\xe5\x91\xa8\xe9\x87\x91\xe4\xb9\x89\n'
一个函数:isinstance()
>>> a='周金义' >>> u=u'周金义' >>> isinstance(a,unicode) /*判断是否是unicode编码*/ False >>> isinstance(u,unicode) True
回归:
了解了这些之后,那对数据库表的导出脚本:conn.character_set_name() 是显示数据库的链接字符集,可以print出来,例子理显示为lanti1
#!/usr/bin/python #encoding: utf-8 #------------------------------------------------------------------------------- # Name: latin_to_gbk.py # Purpose: latin1 编码转传成 gbk # Author: zhoujy # Created: 2012-10-31 # update: 2012-10-31 #------------------------------------------------------------------------------- import MySQLdb conn = MySQLdb.connect(host='localhost',user='root',passwd='123456',db='phpbb') cursor = conn.cursor() query = "select username,user_company,user_realname from users limit 20" #query = "select post_id,post_subject,post_text from posts_text" cursor.execute(query) conn.commit() items = cursor.fetchall() for line in items: a,b,c = line a=a.decode('gbk') b=b.decode('gbk') c=c.decode('gbk') # print a.encode('utf-8'),b.encode('utf-8'),c.encode('utf-8') print a,',',b,',',c
结果:
NAME | COMPANY | RNAME |
A | the Feed Institute, CAAS | tiezhengyuan |
B | 湖北省武汉市园 | 小二 |
C | 北京公司 | 大三 |
D | AB | 李逵 |
E | 上海公司 | 宋江 |
F | 中国公司 | 花荣 |
G | 我302从 | 武松 |
H | 上海 | 潘安 |
I | 中国 | 刘备 |
#!/usr/bin/python #encoding: utf-8 #------------------------------------------------------------------------------- # Name: latin_to_gbk.py # Purpose: latin1 编码表转传成gbk编码表 # Author: zhoujy # Created: 2012-10-31 # update: 2012-10-31 #------------------------------------------------------------------------------- import MySQLdb MySQLdb.escape_string def convert_code(s): #转换 if s == None or s == '': s = '' return MySQLdb.escape_string(str(s).decode('gbk').encode('gbk')) else: return MySQLdb.escape_string(str(s).decode('gbk').encode('gbk')) def get_data(conn): query =''' select user_id,username from users ''' cursor = conn.cursor() cursor.execute(query) items = cursor.fetchall() return items def insert_data(tconn,items): for line in items: a,b = line #异常处理,错误继续,增加容错,否则错误就退出了。 try: query = ''' insert into php_users(user_id,username) values(%s,"%s") ''' %(a,convert_code(b)) # print query cursor = tconn.cursor() cursor.execute('set names gbk') cursor.execute(query) tconn.commit() except Exception,e: print "userId : " + str(a) print e continue if __name__ =='__main__': conn = MySQLdb.connect(host='192.168.1.10',user='root',passwd='123456',db='bb') tconn = MySQLdb.connect(host='192.168.1.20',user='root',passwd='123456',db='cc') items = get_data(conn) insert_data(tconn,items)
因此,对于数据库方面来讲,遇到乱码时,先要核对set names里的三个参数是什么,再看终端使用什么编码。 都一致的话大部分的情况不会乱码,不能随便用alter table convert to 进行转码,转码的时候一定要先搞明白,字符串str是什么编码(程序转换字符存表的的时候使用的是什么),然后通过脚本(python 中 先把 decode成unicode,然后再encode成其他编码)进行解码,编码。
关于python 的encode与decode 下面有更多信息:
http://cenalulu.github.io/mysql/mysql-mojibake 值得一看
http://blog.csdn.net/lf8289/article/details/2465196
http://blog.csdn.net/lxdcyh/article/details/4018054
http://www.cnblogs.com/evening/archive/2012/04/19/2457440.html
关于MySQL乱码: http://blog.csdn.net/yah99_wolf/article/details/7391089
相关文章推荐
- 数据库乱码问题 & Python 编码问题(Unicode 的 encode、decode 相互转换 )
- 如何解决python连接数据库编码问题(python传数据到mysql乱码)'ascii' codec can't encode _mysql_exceptions.OperationalError: (1366, "Incorrect string value:?
- python编码问题之\"encode\"&\"decode\"
- python中的编码问题unicode, encode, decode
- Python编码相关问题 Unicode UTF-8 encode() decode()
- python编码问题 decode('unicode-escape')
- python编码问题之\"encode\"&\"decode\"
- python编码问题之\"encode\"&\"decode\"
- python 字符串编码 str和unicode 区别以及相互转化 decode('utf-8') encode('utf-8')
- Python字符串的encode与decode研究心得乱码问题解决方法(很多的编码问题都可以从此得出答案)
- python 编码乱码问题(decode,encode)
- python蛋疼的编码decode、encode、unicode、str、byte的问题都在这了
- Python字符串的encode与decode研究心得——解决乱码问题
- 8.python中字符串的编码和解码问题——decode/encode
- tomcat服务器乱码问题,tomcat与数据库之间的编码统一转换
- Python字符串的encode与decode研究心得乱码问题解决方法
- python字符串的encode与decode研究心得——解决乱码问题
- 解决python3 UnicodeEncodeError: 'gbk' codec can't encode 或者decode等问题
- Python字符串的encode与decode乱码问题
- python中文的编码问题(使用decode('gbk').encode('utf-8')和decode('utf-8').encode('gbk'))