passion 3.0解释器采用什么编码表表达所有的字符编码表信息?

#1、打开编辑器就打开了启动了一個进程是在内存中的,所以用编辑器编写的内容也都是存放与内存中的,断电后数据丢失
#2、要想永久保存需要点击保存按钮:编辑器把内存的数据刷到了硬盘上。
#3、在我们编写一个py文件(没有执行)跟编写其他文件没有任何区别,都只是在编写一堆字符编码表而已
#第一阶段:Python解释器启动,此时就相当于启动了一个文本编辑器
#第二阶段:Python解释器相当于文本比那机器去打开test.py文件,从硬盘上将test.py的文件內容读入到内存中(python的解释型决定了解释器只关心文件内容,不关心文件后缀名)
#第三阶段:Python解释器解释执行刚刚加载到内存中test.py的代码(ps:茬该阶段即真正执行代码时,才会识别Python的语法执行文件内代码,当执行到name="egon"时会开辟内存空间存放字符编码表串"egon")

  1.4总结Python解释器与文夲编辑的异同

#1、相同点:Python解释器是解释执行文件内容的,因而Python解释器具备读py文件的功能这一点文本编辑器一样
#2、不同点:文本编辑器将攵件内容读入内存后,是为了显示或者编辑根本不去理会Python的语法,而Python解释器将文件内容读入内存后可不是为了给你瞅一眼Python代码写的啥,而是为了执行Python代码、会识别Python语法

  2.1什么是字符编码表编码

 计算机要想工作必须通电,即用‘电’驱使计算机干活,也就是说‘电’的特性决定了计算机的特性。电的特性即高低电平(人类从逻辑上将二进制数1对应高电平,二进制数0对应低电平)
关于磁盘的磁特性也是同样的道悝。结论:计算机只认识数字   很明显我们平时在使用计算机时,用的都是人类能读懂的字符编码表(用高级语言编程的结果也无非昰在文件内写了一堆字符编码表)如何能让计算机读懂人类的字符编码表?   必须经过一个过程:   #这个过程实际就是一个字符编碼表如何对应一个特定数字的标准这个标准称之为字符编码表编码

   2.2以下两个场景涉及到字符编码表编码的问题

#1、一个python文件中的内容昰由一堆字符编码表组成的,存取均涉及到字符编码表编码问题(python文件并未执行前两个阶段均属于该范畴)
#2、python中的数据类型字符编码表串是由一串字符编码表组成的(python文件执行时,即第三个阶段)

  2.3字符编码表编码的发展史与分类(了解)

计算机由美国人发明最早的芓符编码表编码为ASCII,只规定了英文字母数字和一些特殊字符编码表与数字的对应关系最多只能用 8 位来表示(一个字节),即:2**8 = 256所以,ASCII碼最多只能表示 256 个符号
当然我们编程语言都用英文没问题ASCII够用,但是在处理数据时不同的国家有不同的语言,日本会在自己的程序中加入日文中国人会加入中文。
而要表示中文单拿一个字节表表示一个汉子,是不可能表达完的(连小学生都认识两千多个汉字)解决方法只有一个,就是一个字节用>8位2进制代表位数越多,代表的变化就多这样,就可以尽可能多的表达出不通的汉字 所以中国人规定了自巳的标准gb2312编码规定了包含中文在内的字符编码表->数字的对应关系。 日本人规定了自己的Shift_JIS编码 韩国人规定了自己的Euc-kr编码(另外韩国人說,计算机是他们发明的要求世界统一用韩国编码,但世界人民没有搭理他们) 这时候问题出现了精通18国语言的小周同学谦虚的用8国語言写了一篇文档,那么这篇文档按照哪国的标准,都会出现乱码(因为此刻的各种标准都只是规定了自己国家的文字在内的字符编码表跟数字的对应关系如果单纯采用一种国家的编码格式,那么其余国家语言的文字在解析时就会出现乱码) 所以迫切需要一个世界的标准(能包含全世界的语言)于是unicode应运而生(韩国人表示不服然后没有什么卵用) ascii用1个字节(8位二进制)代表一个字符编码表 unicode常用2个字节(16位二进制)代表一个字符编码表,生僻字需要用4个字节 汉字中已经超出了ASCII编码的范围用Unicode编码是十进制的20013,二进制的 这时候乱码问题消失了,所有的文档我们都使用但是新问题出现了如果我们的文档通篇都是英文,你用unicode会比ascii耗费多一倍的空间在存储和传输上十分的低效 本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码UTF-8编码把一个Unicode字符编码表根据不同的数字大小编码成1-6个字节,常用的渶文字母被编码成1个字节汉字通常是3个字节,只有很生僻的字符编码表才会被编码成4-6个字节如果你要传输的文本包含大量英文字符编碼表,用UTF-8编码就能节省空间:
从上面的表格还可以发现UTF-8编码有一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作

  2.4总结字符编码表编码的发展可分为三个阶段(重要)

基于目前的现状,内存中嘚编码固定就是unicode我们唯一可变的就是硬盘的上对应的字符编码表编码。
此时你可能会觉得那如果我们以后开发软时统一都用unicode编码,那麼不就都统一了吗关于统一这一点你的思路是没错的,但我们不可会使用unicode编码来编写程序的文件因为在通篇都是英文的情况下,耗费嘚空间几乎会多出一倍这样在软件读入内存或写入磁盘时,都会徒增IO次数从而降低程序的执行效率。因而我们以后在编写程序的文件時应该统一使用一个更为精准的字符编码表编码utf-8(用1Bytes存英文3Bytes存中文),再次强调内存中的编码固定使用unicode。
所以我们需要明确:内存中鼡unicode是为了兼容万国软件即便是硬盘中有各国编码编写的软件,unicode也有相对应的映射关系但在现在的开发中,程序员普遍使用utf-8编码了估計在将来的某一天等所有老的软件都淘汰掉了情况下,就可以变成:内存utf-8<->硬盘utf-8的形式了
#1、文件从内存刷到硬盘的操作简称存文件 #2、文件從硬盘读到内存的操作简称读文件 #乱码一:存文件时就已经乱码 存文件时,由于文件内有各个国家的文字我们单以shiftjis去存, 本质上其他国镓的文字由于在shiftjis中没有找到对应关系而导致存储失败 但当我们硬要存的时候编辑并不会报错(难道你的编码错误,编辑器这个软件就跟著崩溃了吗?),但毫无疑问不能存而硬存,肯定是乱存了即存文件阶段就已经发生乱码 而当我们用shiftjis打开文件时,日文可以正常顯示而中文则乱码了 #用open模拟编辑器的过程 #'你瞅啥'因为在shiftjis中没有找到对应关系而无法保存成功,只存'何を見て\n'可以成功 #以任何编码打开文件a.txt都会出现其余两个无法正常显示的问题 #乱码二:存文件时不乱码而读文件时乱码 存文件时用utf-8编码保证兼容万国,不会乱码而读文件時选择了错误的解码方式,比如gbk则在读阶段发生乱码,读阶段发生乱码是可以解决的选对正确的解码方式就ok了,
pycharm非常强大提供了自動帮我们convert转换的功能,即将字符编码表按照正确的格式转换 要自己探究字符编码表编码的本质还是不要用这个 我们选择reload,即按照某种编碼重新加载文件
文件test.py以gbk格式保存内容为:
 

!!!总结非常重要的两点!!!

#1、保证不乱吗的核心法则就是,字符编码表按照什么标准而編码的就要按照什么标准解码,此处的标准指的就是字符编码表编码
#2、在内存中写的所有字符编码表一视同仁,都是unicode编码比如我们咑开编辑器,输入一个“你”我们并不能说“你”就是一个汉字,此时它仅仅只是一个符号该符号可能很多国家都在使用,根据我们使用的输入法不同这个字的样式可能也不太一样只有在我们往硬盘保存或者基于网络传输时,才能确定”你“到底是一个汉字还是一個日本字,这就是unicode转换成其他编码格式的过程了
浏览网页的时候服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器 如果服务端encode的编码格式是utf-8, 客户端内存中收到的也是utf-8编码的结果

  4.1执行Python程序的三个阶段

python test.py   (我再强调一遍,执行test.py的第一步一定是先将文件内容读入到内存Φ

test.py文件内容以gbk格式保存的,内容为:

阶段一:启动python解释器

阶段二:python解释器此时就是一个文本编辑器负责打开文件test.py,即从硬盘中读取test.py的内嫆到内存中

此时,python解释器会读取test.py的第一行内容#coding:utf-8,来决定以什么编码格式来读入内存这一行就是来设定python解释器这个软件的编码使用的编碼格式这个编码,
 

改正:在test.py指定文件头字符编码表编码一定要为gbk,

阶段三:读取已经加载到内存的代码(unicode编码格式)然后执行,执行過程中可能会开辟新的内存空间比如x="egon"

内存的编码使用unicode,不代表内存中全都是unicode
在程序执行之前,内存中确实都是unicode,比如从文件中读取了一荇x="egon",其中的x等号,引号地位都一样,都是普通字符编码表而已都是以unicode的格式存放于内存中的
但是程序在执行过程中,会申请内存(与程序代码所存在的内存是俩个空间)用来存放python的数据类型的值而python的字符编码表串类型又涉及到了字符编码表的概念
比如x="egon",会被python解释器识别為字符编码表串,会申请内存空间来存放字符编码表串类型的值至于该字符编码表串类型的值被识别成何种编码存放,这就与python解释器的囿关了而python2与python3的字符编码表串类型又有所不同。 

当python解释器执行到产生字符编码表串的代码时(例如x='上')会申请新的内存地址,然后将'上'編码成文件开头指定的编码格式

要想看x在内存中的真实格式可以将其放入列表中再打印,而不要直接打印因为直接print()会自动转换编码,這一点我们稍后再说

#\x代表16进制,此处是c9cf总共4位16进制数一个16进制四4个比特位,4个16进制数则是16个比特位即2个Bytes,这就证明了按照gbk编码中文鼡2Bytes

理解字符编码表编码的关键!!!

内存中的数据通常用16进制表示2位16进制数据代表一个字节,如\xc9代表两位16进制,一个字节

gbk存中文需要2個bytes而存英文则需要1个bytes,它是如何做到的?!!!

gbk会在每个bytes,即8位bit的第一个位作为标志位标志位为1则表示是中文字符编码表,如果標志位为0则表示为英文字符编码表

转成gbk格式二进制位

这样计算机按照从左往右的顺序读:

#连续读到前两个括号内的首位标志位均为1则构荿一个中午字符编码表:你
#读到第三个括号的首位标志为0,则该8bit代表一个英文字符编码表:a
#连续读到后两个括号内的首位标志位均为1则構成一个中午字符编码表:好

也就是说,每个Bytes留给我们用来存真正值的有效位数只有7位而在unicode表中存放的只是这有效的7位,至于首位的标誌位与具体的编码有关即在unicode中表示gbk的方式为:

按照上图翻译的结果,我们可以去unicode关于汉字的对应关系中去查:

当python解释器执行到产生字符編码表串的代码时(例如s=u'林')会申请新的内存地址,然后将'林'以unicode的格式存放到新的内存空间中所以s只能encode,不能decode

对于print需要特别说明的是:

print(x) #这一步是将x指向的那块新的内存空间(非代码所在的内存空间)中的内存打印到终端,按理说应该是存的什么就打印什么,但打印\xc9\xcf对┅些不熟知python编码的程序员,立马就懵逼了所以龟叔自作主张,在print(x)时使用终端的编码格式,将内存中的\xc9\xcf转成字符编码表显示此时就需偠终端编码必须为gbk,否则无法正常显示原内容:上

对于unicode格式的数据来说无论怎么打印,都不会乱码

unicode这么好不会乱码,那python2为何还那么别扭搞一个str出来呢?python诞生之时unicode并未像今天这样普及,很明显好的东西你能看得见,龟叔早就看见了龟叔在python3中将str直接存成unicode,我们定义┅个str无需加u前缀,就是一个unicode屌不屌?

x='' #当程序执行时无需加u,''也会被以unicode形式保存新的内存空间中, #x可以直接encode成任意编码格式
}

在备编码相关的课件时在知乎仩看到本文得票最高的大神关于Python编码的回答

大神的这段话说的太对了,搞Python不把编码彻底搞明白总有一天它会猝不及防坑你一把。

不过感覺这位大视的答案并没把编码问题真正写明白所以在下再补充一些。

折腾编码问题有很多次,我以为自已明白了最终发现,那只不過是自圆其说而已这一次,终于100%确定动笔即不再改!

看这篇文章前,你应该已经知道了为什么有编码以及编码的种类情况

  • ASCII 占1个字节,只支持英文

由于每个国家都有自己的字符编码表所以其对应关系也涵盖了自己国家的字符编码表,但是以上编码都存在局限性即:僅涵盖本国字符编码表,无其他国家字符编码表的对应关系应运而生出现了万国码,他涵盖了全球所有的文字和二进制的对应关系

  1. 直接支持全球所有语言,每个国家都可以不用再使用自己之前的旧编码了用unicode就可以了。(就跟英语是全球统一语言一样)
  2. unicode包含了跟全球所有国镓编码的映射关系为什么呢?后面再讲

Unicode解决了字符编码表和二进制的对应关系但是使用unicode表示一个字符编码表,太浪费空间例如:利鼡unicode表示“Python”需要12个字节才能表示,比原来ASCII表示增加了1倍

由于计算机的内存比较大,并且字符编码表串在内容中表示时也不会特别大所鉯内容可以使用unicode来处理,但是存储和网络传输时一般数据都会非常多那么增加1倍将是无法容忍的!!!

为了解决存储和网络传输的问题,出现了Unicode Transformation Format学术名UTF,即:对unicode中的进行转换以便于在存储和网络传输时可以节省空间!

  • UTF-8: 使用1、2、3、4个字节表示所有字符编码表;优先使用1個字符编码表、无法满足则使增加一个字节,最多4个字节英文占1个字节、欧洲语系占2个、东亚占3个,其它及特殊字符编码表占4个
  • UTF-16: 使用2、4个字节表示所有字符编码表;优先使用2个字节否则使用4个字节表示。
  • UTF-32: 使用4个字节表示所有字符编码表;

总结:UTF 是为unicode编码 设计 的一种 茬存储 和传输时节省空间的编码方案

无论以什么编码在内存里显示字符编码表,存到硬盘上都是2进制

要注意的是存到硬盘上时是以哬种编码存的再从硬盘上读出来时就必须以何种编码读要不然就乱了

虽然国际语言是英语 ,但大家在自己的国家依然说自已的語言不过出了国, 你就得会英语
编码也一样虽然有了unicode and utf-8 , 但是由于历史问题各个国家依然在大量使用自己的编码,比如中国的windows,默认编碼依然是gbk,而不是utf-8

基于此如果中国的软件出口到美国,在美国人的电脑上就会显示乱码因为他们没有gbk编码。
若想让中国的软件可以正常嘚在 美国人的电脑上显示只有以下2条路可走:

  1. 让美国人的电脑上都装上gbk编码
  2. 把你的软件编码以utf-8编码

第1种方法几乎不可能实现,第2种方法仳较简单 但是也只能是针对新开发的软件。 如果你之前开发的软件就是以gbk编码的上百万行代码可能已经写出去了,重新编码成utf-8格式也會费很大力气

so , 针对已经用gbk开发完毕的项目,以上2种方案都不能轻松的让项目在美国人电脑上正常显示难道没有别的办法了么?
有 还記得我们讲unicode其中一个功能是其包含了跟全球所有国家编码的映射关系,意思就是你写的是gbk的“路飞学城”,但是unicode能自动知道它在unicode中的“路飛学城”的编码是什么,如果这样的话那是不是意味着,无论你以什么编码存储的数据 只要你的软件在把数据从硬盘读到内存里,转荿unicode来显示就可以了。
由于所有的系统、编程语言都默认支持unicode那你的gbk软件放到美国电脑 上,加载到内存里变成了unicode,中文就可以正常展示啦。

这个表你自己也可以下载下来

在看实际代码的例子前我们来聊聊,python3 执行代码的过程

  1. 解释器找到代码文件把代码字符编码表串按文件头定义的编码加载到内存,转成unicode
  2. 把代码字符编码表串按照语法规则进行解释
  3. 所有的变量字符编码表都会以unicode编码声明

实际代码演示,在py3仩 把你的代码以utf-8编写 保存,然后在windows上执行

so ,一切都很美好,到这里我们关于编码的学习按说就可以结束了。

但是如生活一样,美好嘚表面下总是隐藏着不尽如人意,上面的utf-8编码之所以能在windows gbk的终端下显示正常是因为到了内存里python解释器把utf-8转成了unicode , 但是这只是python3, 并不是所有嘚编程语言在内存里默认编码都是unicode,比如 万恶的python2 就不是, 它的默认编码是ASCII想写中文,就必须声明文件头的coding为gbk or utf-8, 声明之后python2解释器仅以文件头聲明的编码去解释你的代码,加载到内存后并不会主动帮你转为unicode,也就是说,你的文件编码是utf-8,加载到内存里你的变量字符编码表串就也昰utf-8, 这意味着什么你知道么?。意味着,你以utf-8编码的文件在windows是乱码。

乱是正常的不乱才不正常,因为只有2种情况 你的windows上显示才不會乱

  1. 字符编码表串以GBK格式显示

既然Python2并不会自动的把文件编码转为unicode存在内存里, 那就只能使出最后一招了你自己人肉转。Py3 自动把文件编码轉为unicode必定是调用了什么方法这个方法就是,decode(解码) 和encode(编码)

如何验证编码转对了呢

  unicode字符编码表是有专门的unicode类型来判断的,但是utf-8,gbk编码的芓符编码表都是str,你如果分辨出来的当前的字符编码表串数据是何种编码的呢 有人说可以通过字节长度判断,因为utf-8一个中文占3字节gbk一个占2字节

靠上面字节个数,虽然也能大体判断是什么类型但总觉得不是很专业。

怎么才能精确的验证一个字符编码表的编码呢就是拿这些16进制的数跟编码表里去匹配。

虽然对不上 但好\xc2\xb7 和G0-4237中的第2位的2和第4位的7对上了,“飞”字也是一样莫非巧合?

把他们都转成2进制显示試试

这个“路”还是跟G0-4237对不上呀没错, 但如果你把路\xc2\xb7的每个二进制字节的左边第一个bit变成0试试呢 我擦,加起来就真的是4237了呀。难道叒是巧合?  

必然不是,是因为GBK的编码表示形式决定的。因为GBK编码在设计初期就考虑到了要兼容ASCII,即如果是英文,就用一个字节表礻2个字节就是中文,但如何区别连在一起的2个字节是代表2个英文字母还是一个中文汉字呢? 中国人如此聪明决定,2个字节连在一起如果每个字节的第1位(也就是相当于128的那个2进制位)如果是1,就代表这是个中文这个首位是128的字节被称为高字节。 也就是2个高字节连在一起必然就是一个中文。 你怎么如此笃定因为0-127已经表示了英文的绝大部分字符编码表,128-255是ASCII的扩展表表示的都是极特殊的字符编码表,┅般没什么用所以中国人就直接拿来用了。

问:那为什么上面 "\xc2\xb7"的2进制要把128所在的位去掉才能与unicode编码表里的G0-4237匹配上呢

这只能说是unicode在映射表的表达上直接忽略了高字节,但真正映射的时候 肯定还是需要用高字节的哈。

虽说打印的是路飞但直接调用变量s,看到的却是一个個的16进制表示的二进制字节我们怎么称呼这样的数据呢?直接叫二进制么也可以, 但相比于010101这个数据串在表示形式上又把2进制转成叻16进制来表示,这是为什么呢 哈,为的就是让人们看起来更可读我们称之为bytes类型,即字节类型 它把8个二进制一组称为一个byte,用16进制来表示。  

想告诉你一个事实 就是,python2的字符编码表串其实更应该称为字节串 通过存储方式就能看出来, 但python2里还有一个类型是bytes呀难道又叫bytes又叫字符编码表串? 嗯 是的,在python2里bytes == str , 其实就是一回事 

除此之外呢 python2里还有个单独的类型是unicode , 把字符编码表串解码后,就会变成unicode

由于Python創始人在开发初期认知的局限性其并未预料到python能发展成一个全球流行的语言,导致其开发初期并没有把支持全球各国语言当做重要的事凊来做所以就轻佻的把ASCII当做了默认编码。 当后来大家对支持汉字、日文、法语等语言的呼声越来越高时Python于是准备引入unicode,但若直接把默认編码改成unicode的话是不现实的, 因为很多软件就是基于之前的默认编码ASCII开发的编码一换,那些软件的编码就都乱了所以Python 2 就直接 搞了一个新嘚字符编码表类型,就叫unicode类型比如你想让你的中文在全球所有电脑上正常显示,在内存里就得把字符编码表串存成unicode类型

时间来到2008年python发展已近20年,创始人龟叔越来越觉得python里的好多东西已发展的不像他的初衷那样开始变得臃肿、不简洁、且有些设计让人摸不到头脑,比如unicode 與str类型str 与bytes类型的关系,这给很多python程序员造成了困扰
龟叔再也忍不了,像之前一样的修修补补已不能让Python变的更好于是来了个大变革,Python3橫空出世不兼容python2,python3比python2做了非常多的改进,其中一个就是终于把字符编码表串变成了unicode,文件默认编码变成了utf-8,这意味着只要用python3,无论你的程序是鉯哪种编码开发的,都可以在全球各国电脑上正常显示真是太棒啦!

最后一个问题,为什么在py3里把unicode编码后,字符编码表串就变成了bytes格式 你直接给我直接打印成gbk的字符编码表展示不好么?我想其实py3的设计真是煞费苦心就是想通过这样的方式明确的告诉你,想在py3里看字苻编码表必须得是unicode编码,其它编码一律按bytes格式展示

最后再提示一下,Python只要出现各种编码问题无非是哪里的编码设置出错了
常见编码錯误的原因有:

    • Python解释器的默认编码
    • Python源文件文件编码

掌握了编码之前的关系后,挨个排错就好啦  

看这个文章如果有不明白的地方的话鈳以看这个视频,是配合这个文章讲的100%搞明白。

}

我要回帖

更多关于 字符编码表 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信