python字符串编码
python默认编码
python 2.x默认的字符编码是ASCII,默认的⽂件编码也是ASCII。
python 3.x默认的字符编码是unicode,默认的⽂件编码是utf-8。
中⽂乱码问题
⽆论以什么编码在内存⾥显⽰字符,存到硬盘上都是⼆进制,所以编码不对,程序就会出错。
常见编码有ascii编码(美国),GBK编码(中国),shift_JIS编码(⽇本),unicode(统⼀编码)等。
需要注意的是,存到硬盘上时是以何种编码存的,再从硬盘上读出来时,就必须以何种编码读,要不然就会出现乱码问题。
常见的编码错误的原因有如下,出现乱码时,按照编码之前的关系,挨个排错就能解决问题。
python解释器的默认编码;
Terminal使⽤的编码;
python源⽂件⽂件编码;
操作系统的语⾔设置。
Python⽀持中⽂的编码:utf-8、gbk和gb2312。uft-8为国际通⽤,常⽤有数据库、编写代码。gbk如windows的cmd使⽤。
编码转换
如果想要中国的软件可以正常的在美国⼈的电脑上实现,有下⾯两种⽅法:
让美国⼈的电脑都装上gbk编码
让你的软件编码以utf-8编码
第⼀种⽅法不可现实,第⼆种⽅法⽐较简单,但是也只能针对新开发的软件,如果之前开发的软件就是以gbk的编码写的,上百万⾏代码已经写出去了,重新编码成utf-8格式也会费很⼤⼒⽓。
所以,针对已经⽤gbk开发的软件项⽬如何进⾏编码转换,利⽤unicode的⼀个包含了跟全球所有国家
编码映射关系的功能,就可以实现编码转换。⽆论以什么编码存储的数据,只要我们的软件把数据从硬盘上读到内存,转成unicode来显⽰即可,由于所有的系统、编程语⾔都默认⽀持unicode,所有我们的gbk编码软件放在美国电脑上,加载到内存⾥⾯,变成了unicode,中⽂就可正常展⽰。
类似⽤如下的转码的过程:
源有编码 -> unicode编码 -> ⽬的编码
decode("UTF-8") 解码 --> unicode --> encode("gbk") 编码
#_*_coding:utf-8_*_ 的作⽤
在python2⽂件中,经常在⽂件开头看到“ #_*_coding:utf-8 _*_ ”语句,它的作⽤是告诉python解释器此.py⽂件是utf-8编码,需要⽤utf-8的编码去读取这个.py⽂件。
python2.x的bytes与python3.x的bytes的区别
Python2将string处理为原⽣的bytes类型,⽽不是 unicode。⽽Python3所有的 string均是unicode类型。
在python2.x中,写字符串,⽐如
>>>s = ”学习“
>>>print s
学习
>>>s # 字节类型
'\xd1\xa7\xcf\xb0'
虽然说打印的是中⽂学习,但是直接调⽤变量s时,显⽰的却是⼀个个16进制表⽰的⼆进制字节,我们称这个为byte类型,即字节类型,它把8个⼆进制组成⼀个byte,⽤16进制表⽰。
所以说python2.x的字符串其实更应该称为字符串,通过存储的⽅式就能看出来,但是在python2.x中还有⼀个bytes类型,两个是否相同呢,回答是肯定的,在python2.x中,bytes==str。
python3.x中,把字符串变成了unicode,⽂件默认编码为utf-8。这意味着,只要⽤python3.x,⽆论我们的程序以那种语⾔开发,都可以在全球各国电脑上正常显⽰。
python3.x除了把字符串的编码改成了unicode,还把str和bytes做了明确区分,str就是unicode格式的
字符串,⽽bytes就是单纯的⼆进制。(补充⼀个问题,在python3.x中,只要把unicode编码,字符串就会变成了bytes格式,也不直接打印成gbk的字符,我觉得就是想通过这样的⽅式明确的告诉你,想在python3.x中看字符串,必须是unicode,其他编码⼀律是bytes格式)。
深⼊中⽂编码问题
python3内部使⽤的是unicode编码,⽽外部却要⾯对千奇百怪的各种编码,⽐如作为中国程序经常要⾯对的gbk,gb2312,utf8等,那这些编码是怎么转换成内部的unicode呢?
⾸先看⼀下源代码⽂件中使⽤字符串的情况。源代码⽂件作为⽂本⽂件就必然是以某种编码形式存储代码的,python2默认源代码⽂件是asci编码,python3默认源代码⽂件是utf-8编码。⽐如给python2代码⽂件中的⼀个变量赋值:
s1 = 'a'
print s1
python2认为这个字符'a'就是⼀个asci编码的字符,这个⽂件可以正常执⾏,并打印出'a'字符。在仅仅使⽤英⽂字符的情况下⼀切正常,但是如果⽤了中⽂,⽐如:
s1 = '哈哈'
print s1
这个代码⽂件被执⾏时就会出错,就是编码出了问题。python2默认将代码⽂件内容当作asci编码处理,但asci编码中不存在中⽂,因此抛出异常。
解决问题之道就是要让python2解释器知道⽂件中使⽤的是什么编码形式,对于中⽂,可以⽤的常见编码有utf-8,gbk和gb2312等。只需在代码⽂件的最前端添加如下:
# -*- coding: utf-8 -*-
这就是告知python2解释器,这个⽂件⾥的⽂本是⽤utf-8编码的。这样,python就会依照utf-8的编码形式解读其中的字符,然后转换
成unicode编码内部处理使⽤。
不过,如果你在Windows控制台下运⾏此代码的话,虽然程序是执⾏了,但屏幕上打印出的却不是哈哈字。这是由于python2编码与控制台编码的不⼀致造成的。Windows下控制台中的编码使⽤的是gbk,⽽在代码中使⽤的utf-8,python2按照utf-8编码打印到gbk编码的控制台下⾃然就会不⼀致⽽不能打印出正确的汉字。
解决办法⼀个是将源代码的编码也改成gbk,也就是代码第⼀⾏改成:
# -*- coding: gbk -*-
另⼀种⽅法是保持源码⽂件的utf-8不变,⽽是在’哈哈’前⾯加个u字,也就是:
s1=u’哈哈’
print s1
这样就可以正确打印出’哈哈’字了。这⾥的这个u表⽰将后⾯跟的字符串以unicode格式存储。python2会根据代码第⼀⾏标称的utf-8编码,识别代码中的汉字’哈哈’,然后转换成unicode对象。如果我们⽤type查看⼀下’哈哈’的数据类型type(‘哈哈’),会得到<type ‘str’>,
⽽type(u’哈哈’),则会得到<type ‘unicode’>。
>>> type('哈哈')
<type 'str'>
>>> type(u'哈哈')
unicode码和ascii码区别<type 'unicode'>
也就是在字符前⾯加u就表明这是⼀个unicode对象,这个字会以unicode格式存在于内存中,⽽如果不加u,表明这仅仅是⼀个使⽤某种编码的字符串,编码格式取决于python2对源码⽂件编码的识别,这⾥就是utf-8。
Python2在向控制台输出unicode对象的时候会⾃动根据输出环境的编码进⾏转换,但如果输出的不是unicode对象⽽是普通字符串,则会直接按照字符串的编码输出字符串,从⽽出现上⾯的现象。
使⽤unicode对象的话,除了这样使⽤u标记,还可以使⽤unicode类以及字符串的encode和decode⽅法。
unicode类的构造函数接受⼀个字符串参数和⼀个编码参数,将字符串封装为⼀个unicode,⽐如在这⾥,由于我们⽤的是utf-8编码,所以unicode中的编码参数使⽤'utf-8',将字符封装为unicode对象,然后正确输出到控制台:
s1=unicode(‘哈’, ‘utf-8′)
print s1
另外,⽤decode函数也可以将⼀个普通字符串转换为unicode对象。很多⼈都搞不明⽩python2字符串的decode和encode函数都是什么意思。这⾥简要说明⼀下。
decode函数是将普通字符串按照参数中的编码格式进⾏解析,然后⽣成对应的unicode对象,⽐如在这⾥我们代码⽤的是utf-8,那么把⼀个字符串转换为unicode对象就是如下形式:
>>> s2 = '哈哈'.decode('utf-8')
>>> type(s2)
<type 'unicode'>
这时,s2就是⼀个存储了’哈哈’字符串的unicode对象,其实就和unicode(‘哈哈’, ‘utf-8′)以及u’哈哈’是相同的。
encode函数正好就是相反的功能,是将⼀个unicode对象转换为参数中编码格式的普通字符串,⽐如下⾯代码:
>>> s3 = unicode('哈哈', 'utf-8').encode('utf-8')
>>> type(s3)
<type 'str'>
或者:
>>> s3 = '哈哈'.decode('utf-8').encode('utf-8')
>>> type(s3)
<type 'str'>
s3现在⼜变回了utf-8的’哈哈’。同样的,也可指定其它编码格式,但要注意的是,⽤什么格式编码,就⽤什么格式解码,否则会出现中⽂乱码问题。
字符编码
⽬前使⽤的编码⽅式有:ASCII码(⼀个字节)、Unicode码(两个字节)、UTF-8码(可变长的编码)。我们已经知道了,字符串也是⼀种数据类型,但是,字符串⽐较特殊的是还有⼀个编码问题。
因为计算机只能处理数字,如果要处理⽂本,就必须先把⽂本转换为数字才能处理。最早的计算机在设计时采⽤8个⽐特(bit)作为⼀个字节(byte),所以,⼀个字节能表⽰的最⼤的整数就是255(⼆进制11111111=⼗进制255),如果要表⽰更⼤的整数,就必须⽤更多的字节。⽐如两个字节可以表⽰的最⼤整数是65535,4个字节可以表⽰的最⼤整数是4294967295。
由于计算机是美国⼈发明的,因此,最早只有127个字符被编码到计算机⾥,也就是⼤⼩写英⽂字母、数字和⼀些符号,这个编码表被称为ASCII编码,⽐如⼤写字母A的编码是65,⼩写字母z的编码是122。但是要处理中⽂显然⼀个字节是不够的,⾄少需要两个字节,⽽且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,⽤来把中⽂编进去。可以想得到的是,全世界有上百种语⾔,⽇本把⽇⽂编
到Shift_JIS⾥,韩国把韩⽂编到Euc-kr⾥,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语⾔混合的⽂本中,显⽰出来会有乱码。因此,Unicode应运⽽⽣。Unicode把所有语⾔都统⼀到⼀套编码⾥,这样就不会再有乱码问题了。Unicode标准也在不断发展,但最常⽤的是⽤两个字节表⽰⼀个字符(如果要⽤到⾮常偏僻的字符,就需要4个字节)。现代操作系统和⼤多数编程语⾔都直接⽀
持Unicode。
现在,捋⼀捋ASCII编码和Unicode编码的区别:ASCII编码是1个字节,⽽Unicode编码通常是2个字节。
字母A⽤ASCII编码是⼗进制的65,⼆进制的01000001;
字符'0'⽤ASCII编码是⼗进制的48,⼆进制的00110000,注意字符'0'和整数0是不同的;
汉字中已经超出了ASCII编码的范围,⽤Unicode编码是⼗进制的20013,⼆进制的01001110 00101101。
可以猜测,如果把ASCII编码的A⽤Unicode编码,只需要在前⾯补0就可以,因此,A的Unicode编码是00000000 01000001。
新的问题⼜出现了:如果统⼀成Unicode编码,乱码问题从此消失了。但是,如果你写的⽂本基本上全部是英⽂的话,⽤Unicode编码⽐ASCII编码需要多⼀倍的存储空间,在存储和传输上就⼗分不划算。
所以,本着节约的精神,⼜出现了把Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把⼀个Unicode字符根据不同的数字⼤⼩编码成1-6个字节,常⽤的英⽂字母被编码成1个字节,汉字通常是3个字节,只有很⽣僻的字符才会被编码成4-6个字节。如果你要传输的⽂本包含⼤量英⽂字符,⽤UTF-8编码就能节省空间:
字符 ASCII Unicode UTF-8
A 01000001 00000000 01000001 01000001
中 x 01001110 00101101 11100100 10111000 10101101
UTF-8编码有⼀个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的⼀部分,所以,⼤量只⽀持ASCII编码的历史遗留软件可以在UTF-8编码下继续⼯作。
编码⽅式
1.ASCII
现在我们⾯临了第⼀个问题:如何让⼈类语⾔,⽐如英⽂被计算机理解?我们以英⽂为例,英⽂中有英⽂字母(⼤⼩写)、标点符号、特殊符号。如果我们将这些字母与符号给予固定的编号,然后将这些编号转变为⼆进制,那么计算机明显就能够正确读取这些符号,同时通过这些编号,计算机也能够将⼆进制转化为编号对应的字符再显⽰给⼈类去阅读。由此产⽣了我们最熟知的ASCII码。ASCII 码使⽤指定的7位或8 位⼆进制数组合来表⽰128 或256 种可能的字符。这样在⼤部分情况下,英⽂与⼆进制的转换就变得容易多了。
2.GB2312
虽然计算机是美国⼈发明的,但是全世界的⼈都在使⽤计算机。现在出现了另⼀个问题:如何让中⽂被计算机理解?这下⿇烦了,中⽂不像拉丁语系是由固定的字母排列组成的。ASCII 码显然没办法解决这个问题,为了解决这个问题,中国国家标准总局1980年发布《信息交换⽤汉字编码字符集》提出
了GB2312编码,⽤于解决汉字处理的问题。1995年⼜颁布了《汉字编码扩展规范》(GBK)。GBK与GB 2312—1980国家标准所对应的内码标准兼容,同时在字汇⼀级⽀持ISO/IEC10646—1和GB 13000—1的全部中、⽇、韩(CJK)汉字,共计20902字。这样我们就解决了计算机处理汉字的问题了。
3.Unicode
现在英⽂和中⽂问题被解决了,但新的问题⼜出现了。全球有那么多的国家不仅有英⽂、中⽂还有阿拉伯语、西班⽛语、⽇语、韩语等等。难不成每种语⾔都做⼀种编码?基于这种情况⼀种新的编码诞⽣了:Unicode。Unicode⼜被称为统⼀码、万国码;它为每种语⾔中的每个字符设定了统⼀并且唯⼀的⼆进制编码,以满⾜跨语⾔、跨平台进⾏⽂本转换、处理的要求。Unicode⽀持欧洲、⾮洲、中东、亚洲(包括统⼀标准的东亚象形汉字和韩国表⾳⽂字)。这样不管你使⽤的是英⽂或者中⽂,⽇语或者韩语,在Unicode编码中都有收录,且对应唯⼀的⼆进制编码。这样⼤家都开⼼了,只要⼤家都⽤Unicode编码,那就不存在这些转码的问题了,什么样的字符都能够解析了。
4.UTF-8
但是,由于Unicode收录了更多的字符,可想⽽知它的解析效率相⽐ASCII码和GB2312的速度要⼤⼤降低,⽽且由于Unicode通过增加⼀个⾼字节对ISO Latin-1字符集进⾏扩展,当这些⾼字节位为0时,
低字节就是ISO Latin-1字符。对可以⽤ASCII表⽰的字符使⽤Unicode并不⾼效,因为Unicode⽐ASCII占⽤⼤⼀倍的空间,⽽对ASCII来说⾼字节的0毫⽆⽤处。为了解决这个问题,就出现了⼀些中间格式的字符集,他们被称为通⽤转换格式,即UTF(Unicode Transformation Format)。⽽我们最常⽤的UTF-8就是这些转换格式中的⼀种。在这⾥我们不去研究UTF-8到底是如何提⾼效率的,你只需要知道他们之间的关系即可。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论