对字符编码的理解
Posted 生如夏花和秋叶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对字符编码的理解相关的知识,希望对你有一定的参考价值。
1.含义
关于人类文明中的语言符号与计算机所认识的0和1之间的一个对应关系表。字符-------通过翻译----------计算机认识的数字。这个过程实际就是一个字符如何对应一个特定数字的标准,这个标准称之为字符编码。同一编码规范的不同版本间具有向下兼容性。
2.发展历史
(1)阶段一:现代计算机起源于美国,最早诞生也是基于英文考虑的ASCII
ASCII:一个Bytes代表一个字符(英文字符/键盘上的所有其他字符),1Bytes=8bit,8bit可以表示0-2**8-1种变化,即可以表示256个字符
ASCII最初只用了后七位,127个数字,已经完全能够代表键盘上所有的字符了(英文字符/键盘的所有其他字符),后来为了将拉丁文也编码进了ASCII表,将最高位也占用了。
(2)阶段二:为了满足中文和英文,中国人定制了GBK。GBK:2Bytes代表一个中文字符,1Bytes表示一个英文字符 为了满足其他国家,各个国家纷纷定制了自己的编码 日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里。
(3)阶段三:各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。如何解决这个问题呢???
说白了乱码问题的本质就是不统一,如果我们能统一全世界,规定全世界只能使用一种文字符号,然后统一使用一种编码,那么乱码问题将不复存在,
ps:就像当年秦始皇统一中国一样,书同文车同轨,所有的麻烦事全部解决
很明显,上述的假设是不可能成立的。很多地方或老的系统、应用软件仍会采用各种各样的编码,这是历史遗留问题。于是我们必须找出一种解决方案或者说编码方案,需要同时满足:
#1、能够兼容万国字符
#2、与全世界所有的字符编码都有映射关系,这样就可以转换成任意国家的字符编码
这就是unicode(定长), 统一用2Bytes代表一个字符, 虽然2**16-1=65535,但unicode却可以存放100w+个字符,因为unicode存放了与其他编码的映射关系,准确地说unicode并不是一种严格意义上的字符编码表,下载pdf来查看unicode的详情:
链接:https://pan.baidu.com/s/1dEV3RYp
很明显对于通篇都是英文的文本来说,unicode的式无疑是多了一倍的存储空间(二进制最终都是以电或者磁的方式存储到存储介质中的)
于是产生了UTF-8(可变长,全称Unicode Transformation Format),对英文字符只用1Bytes表示,对中文字符用3Bytes,对其他生僻字用更多的Bytes去存
#总结:内存中统一采用unicode,浪费空间来换取可以转换成任意编码(不乱码),硬盘可以采用各种编码,如utf-8,保证存放于硬盘或者基于网络传输的数据量很小,提高传输效率与稳定性。
3.涉及到字符编码的场景:
(1)一个python文件中的内容是由一堆字符串组成的,存取均涉及到编码问题;
(2)python中的数据类型字符串是由一串字符组成的;
4.出现乱码的2种情况:
2个概念:文件从内存刷到硬盘叫做存文件:文件从硬盘读到内存叫做读文件
(1)存文件时就已经乱码:存文件时,由于文件内有各个国家的文字,我们单以某一编码格式去存,会存失败而编辑器不会报错,于是打开的时候就会看到乱码
(2)读文件时乱码:存文件时用的是utf-8编码,可以兼容万国,不会乱码,而读文件时选择了错误的解码方式,比如gbk,则在读阶段发生乱码,读阶段发生乱码是可以解决的,选对正确的解码方式就ok了。
5.保证不乱码的方法:用什么格式编码的就就用什么格式解码,一定不会乱码。内存中永远是unicode码。
6.字符编码在文本编辑器中的应用:
7.字符编码在python中的应用:
(1)执行python程序的三个阶段:
第一阶段:启动python解释器
第二阶段:将test.py脚本从硬盘读到内存,此时python解释器就相当于一个文本编辑器,打开test.py文件;此时,python解释器会读取test.py的第一行内容,#coding:utf-8,来决定以什么编码格式来读入内存,这一行就是来设定python解释器这个软件的编码使用的编码格式这个编码。可以用sys.getdefaultencoding()查看,如果不在python文件指定头信息#-*-coding:utf-8-*-,那就使用默认的 python2中默认使用ascii,python3中默认使用utf-8。
第三阶段:读取已经加载到内存中的代码(unicode模式),然后执行过程中可能会开辟新的内存空间,比如x="alex"。请理解好这句话:内存的编码使用unicode,不代表内存中全都是unicode(在程序执行之前,内存中确实都是unicode,比如从文件中读取了一行x="egon",其中的x,等号,引号,地位都一样,都是普通字符而已,都是以unicode的格式存放于内存中的。但是程序在执行过程中,会申请内存(与程序代码所存在的内存是俩个空间)用来存放python的数据类型的值,而python的字符串类型又涉及到了字符的概念。比如x="egon",会被python解释器识别为字符串,会申请内存空间来存放字符串类型的值,至于该字符串类型的值被识别成何种编码存放,这就与python解释器的有关了,而python2与python3的字符串类型又有所不同。python3中“egon"是以unicode码暂存于内存,而python2中是以bytes暂存于内存中的。即python2中,str=bytes,unicode=unicode; python3中,str=unicode,bytes=bytes)。
8.python2与python3字符串类型区别
(1)python2中有2种类型:str 和 unicode。
str类型
当python解释器执行到产生字符串的代码时(例如x=\'上\'),会申请新的内存地址,然后将\'上\'编码成文件开头指定的编码格式
要想看x在内存中的真实格式,可以将其放入列表中再打印,而不要直接打印,因为直接print()会自动转换编码,python解释器这样帮我们做的,易于初学者能看懂,见下面的细说。
#coding:gbk x=\'上\' y=\'下\' print([x,y]) #[\'\\xc9\\xcf\', \'\\xcf\\xc2\'] #\\x代表16进制,此处是c9cf总共4位16进制数,一个16进制四4个比特位,4个16进制数则是16个比特位,即2个Bytes,这就证明了按照gbk编码中文用2Bytes
print(type(x),type(y)) #(<type \'str\'>, <type \'str\'>)
unicode类型
当python解释器执行到产生字符串的代码时(例如s=u\'林\'),会申请新的内存地址,然后将\'林\'以unicode的格式存放到新的内存空间中,所以s只能encode,不能decode
#coding:gbk x=u\'上\' #等同于 x=\'上\'.decode(\'gbk\') y=u\'下\' #等同于 y=\'下\'.decode(\'gbk\') print([x,y]) #[u\'\\u4e0a\', u\'\\u4e0b\'] 注意这一行
print(type(x),type(y)) #(<type \'unicode\'>, <type \'unicode\'>)
打印到终端(细说)
对于print需要特别说明的是:
当程序执行时,比如
x=\'上\' #gbk下,字符串存放为\\xc9\\xcf
print(x) #这一步是将x指向的那块新的内存空间(非代码所在的内存空间)中的内存,打印到终端,按理说应该是存的什么就打印什么,但打印\\xc9\\xcf,对一些不熟知python编码的程序员,立马就懵逼了,所以龟叔自作主张,在print(x)时,使用终端的编码格式,将内存中的\\xc9\\xcf转成字符显示,此时就需要终端编码必须为gbk,否则无法正常显示原内容。
(2)在python3 中也有两种字符串类型str和bytes
str是unicode
#coding:gbk x=\'上\' #当程序执行时,无需加u,\'上\'也会被以unicode形式保存新的内存空间中, print(type(x)) #<class \'str\'> #x可以直接encode成任意编码格式 print(x.encode(\'gbk\')) #b\'\\xc9\\xcf\' print(type(x.encode(\'gbk\'))) #<class \'bytes\'>
很重要的一点是:看到python3中x.encode(\'gbk\') 的结果\\xc9\\xcf正是python2中的str类型的值,而在python3是bytes类型,在python2中则是str类型
于是我有一个大胆的推测:python2中的str类型就是python3的bytes类型,于是我查看python2的str()源码,发现
以上是关于对字符编码的理解的主要内容,如果未能解决你的问题,请参考以下文章