标签:字符编码
一、字符编码历史美国人搞了个ASCII码表,把123abcABC%$#(数字、字母、特殊符号) ,全部用10进制的数字表示。例如数字65,代表着“A” ,ASCII码表一共255个数字,基本代表米国常用英文和符号(其实127以后都不是太常用的了)
中国汉字那么多,255个数字显然不够表示。所以中国人发明了GB2312(6千个常用简体汉字),后来又搞了GBK(2万多汉字,并且包含中日韩中的汉字),再后来又搞了一个GB18030(2.7万汉字,包含中国的少数民族语言)
每个国家不同语言,都需要有自己的编码表,很麻烦。
而且如果日本的软件出口到中国,中国电脑一打开就会乱码(因为没装日本的编码表,软件内文字会乱码)。
再或者,如果一个文件中包含日语、中文、英文,那打开后就乱码了。于是,Unicode国际统一码(2-4个字节)诞生了。 至少用16个2进制表示:11111111 11111111 (2个bytes)
Unicode其实是一张很大的对应关系表,对应着1个字符,在unicode的位置,以及这个字符在ascii码中的位置。
所以,无论你使用何种编码,都能转换成unicode码,而unicode码又能转换成任何其他编码(可以理解unicode左手牵着你编码的字符,右手牵着其他国家的各种编码,额unicode是千手观音,有很多手)。
这样的话,无论你使用GBK、ASCII、或者其他国家对字符进行编码,都能通过这张大表,找到对应其他编码的位置。
使用unicode全球人民都很高兴,终于不再出现乱码了,但是美国、英国人不高兴了。
因为以前他们都使用ASCII码,存一个电影1个GB,现在用Unicode变成了2个GB了(因为ASCII码一共255个数字就可以表示美国人使用的常用字符,255转换成二进制:1111 1111(十进制转二进制),是1个bytes。而Unicode至少2个bytes,所有使用unicode编码的文件,就会比ascii码多一倍大小)
于是乎,为了优化unicode,节省字节。又搞出了UTF-8(英文继续用1个字节,欧洲用2个字节,东南亚用3个字节),注意:使用unicode的时候中文是2个字节,现在使用UTF8变成了3个字节表示了,这占空间啊,很蛋疼,但没办法。
数据文件存到硬盘上是2进制的,像这样: 01010100100101001(尽然没逗号,那计算机怎么断句呢?其实计算机会一次性读取8位2进制,不足8位的补0)
你使用ascii码对你的文件编码,并保存到硬盘。当你打开的时候(就是读到内存的时候),就必须也要指定使用ascii码打开。如果你错误的使用GBK打开,那肯定乱码了。总的来说,什么方式存进去的,什么方式读出来。
总结:在Python3中,无论读取中文、英文或其他国家语言编码的文件,在打印的时候都不会乱码,因为都进行了自动转换,变成了Unicode。(现在的所有操作系统,都支持Unicode编码)
想判断数据类型,使用type()函数。python2中unicode是一种单独的数据类型,而GBK和UTF-8使用type()函数判断类型时,都返回str类型。这样的话,我怎么知道,到底是GBK还是UTF8呢?有人说可以使用len()函数去判断,因为GBK是使用2个字符代表一个中文字,而UTF8使用3个字符代表一个中文字。如下:
#!/usr/bin/env python2.7
#encoding:utf-8
s = "中"
#unicode
s2 = s.decode("utf-8")
print "我运行在python2中,我声明了文件头是UTF8。虽然python2不会自动把我转换成unicode,但我可以自己使用decode函数手工转换,你看,我现在就变成了unicode编码了,我在python2中表现的数据类型是:%s " %type(s2)
#GBK
s3 = s2.encode("gbk") #注意:s2经过上一步的转换,已经变成了unicode编码了。s3现在相当于,在用encode函数把unicode编码成了GBK。
print "我是gbk编码的,我在python2中的数据类型是:%s, 我的长度是:%s" % (type(s3),len(s3))
#UTF8
s4 = s2.encode("utf-8")
print "我是utf-8编码的,我在python2中的数据类型是:%s , 我的长度是:%s " %(type(s4),len(s4))
#运行结果:
我运行在python2中,我声明了文件头是UTF8。虽然python2不会自动把我转换成unicode,但我可以自己使用decode函数手工转换,你看,我现在就变成了unicode编码了,我在python2中表现的数据类型是:<type ‘unicode‘>
我是gbk编码的,我在python2中的数据类型是:<type ‘str‘>, 我的长度是:2
我是utf-8编码的,我在python2中的数据类型是:<type ‘str‘> , 我的长度是:3
问题确实存在,gbk编码、utf-8编码,在python2中的数据类型都是str。
我如何知道一个字符串到底是gbk编码的还是utf8编码的呢?
虽然可以看长度,gbk用2个字节,代表1个中文,utf-8用3个字节,代表1个中文汉字。这没错,那是因为举得例子简单,如果无数个字节,比如这样:‘\xd6\xd0...bulabulabula一大堆‘,让你判断,这些字节的编码是什么?那怎么办呢?
>>> s = "中"
>>> s_unicode = s.decode("utf-8")
>>> s_unicode
u‘\u4e2d‘
>>>
>>> s_gbk = s_unicode.encode("gbk")
>>> s_gbk
‘\xd6\xd0‘
>>>
>>> s_utf8 = s_unicode.encode("utf-8")
>>> s_utf8
‘\xe4\xb8\xad‘
总结下,这个"中"字:
unicode编码是长这样: u‘\u4e2d‘
gbk编码是长这样的: ‘\xd6\xd0‘
UTF8编码是长这样的: ‘\xe4\xb8\xad‘
\xd6\xd0 中的d6,11010110(2进制)--->1101 0110--->去掉每组第1位不算--->0101 0110--->转成16进制--->56
首先:GBK是每2个字节代表1个中文,ASCII码是1个字节代表1个英文字母的。
如果给你一个2个2进制(2个字节)11010110 11010000,你怎知道是代表1个中文,还是2个ASCII码的英文字符呢?
正好,ASCII码常用的就127个,7位2进制最大就是127,就可以表示了,还剩下1位。
中国人设计GBK的时候,考虑到想兼容ASCII码。想到,既然ASCII码的127往后至255都不常用。那我们利用剩下的这1位做文章。
举例:11010110 11010000 这2个二进制,第1位都被都设置了1,这是个中文。
总结:
python2
>>> s = "中"
>>> print s
中 #称之为字符串 (其实是字形)
>>> s
‘\xe4\xb8\xad‘ #字符串"中"字,在编码表里的位置。 是二进制数据串(只不过16进制表现形式)
其实按理说,print 应该打印 ‘\xe4\xb8\xad‘ 这个位置,但是print帮你打印了这个位置对应的"中"字 (其实这个"中"字就是一个图片字形)
总结:
实例:
#python2里,把bytes类型和字符串类型,都称为字符串"str",不区分,如下:。
>>> s_str = "中"
>>> print type(s_str)
<type ‘str‘> #字符串就是str类型
>>>
>>> s_bytes = b"中" #b"字符串" -->定义一个bytes类型
>>> print type(s_bytes)
<type ‘str‘> #bytes类型 也是 str类型
>>>
Python3的字符串类型是str,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes,像这样:x = b‘ABC‘
#Python3
>>> type("ABC")
<class ‘str‘>
>>> ‘ABC‘.encode(‘ascii‘) #把英文的str变成了bytes
b‘ABC‘
>>> ‘中文‘.encode(‘utf-8‘) #把中文的str变成了bytes
b‘\xe4\xb8\xad\xe6\x96\x87‘
>>> b‘ABC‘.decode(‘ascii‘) #把英文bytes转换成了str
u‘ABC‘
>>> type(b‘ABC‘.decode(‘ascii‘)) #通过type()函数查看,python3中str就是unicode类型。
<type ‘unicode‘>
>>> b‘\xe4\xb8\xad\xe6\x96\x87‘.decode(‘utf-8‘) #把中文的bytes转成str
u‘\u4e2d\u6587‘
>>> print(b‘\xe4\xb8\xad\xe6\x96\x87‘.decode(‘utf-8‘)) #打印时,就可以显示字形了。
中文
#说明:如果bytes中包含无法解码的字节,decode()方法会报错
>>> len(‘ABC‘)
3
>>> len(‘中文‘)
2
>>>
>>> len(b‘ABC‘)
3
>>> len(b‘\xe4\xb8\xad\xe6\x96\x87‘)
6
因为在python2初期开发的时候,就没考虑到全球化问题,默认用的ASCII码。后来python普及后,各国开发者呼吁支持全球化语言,所以python2没办法,单独又造了一个Unicode类型。
#python2实例
>>> s = "str"
>>> s_unicode = s.decode("utf-8") #python2中,unicode类型是单独的。
>>> s_gbk = s_unicode.encode("gbk") #把unicode编码成gbk
>>> type(s_gbk)
<type ‘str‘> #打印时发现,gbk编码的类型显示为str。
#python3实例
>>> s = "str" #python3 字符串str都是unicode
>>> s_gbk = s.encode("gbk") #把unicode编码成gbk
>>> type(s_gbk)
<class ‘bytes‘> #打印时发现, gbk编码的类型是 bytes。(不再和python2一样是str类型了)
结论:
1. 在python2中,str = bytes,之所以多个bytes类型是为了表示图片等二进制流。
2. 在python3中,字符串str就是str字形 (str都是由unicode编码), bytes就是bytes,明确告诉你,你想看字符串str的字形,必须的是unicode编码。而图片二进制流,没办法编码和解码,传输时一律使用bytes类型。
参考链接:
标签:字符编码
原文地址:http://blog.51cto.com/874781040/2088540