一文搞懂Python2与Python3的编码问题(Linux和Windows编码转换)

在这里插入图片描述

前言

搞Python不把编码彻底搞明白,总有一天它会猝不及防坑你一把。python中编码问题一直让人头大,这里好好的记录一下。

一. 什么是编码

  • 用于人类看的文本叫做明文,编码文本通常用于计算机的解释文本。

将明文转换为计算机可以识别的的编码文本称为“编码”, 反之从计算机可识别的编码文本转回明文为“解码”

1、编码的种类情况

  • ASCII 占1个字节,只支持英文
  • GB2312 占2个字节,支持6700+汉字
  • GBK GB2312的升级版,支持21000+汉字
  • Shift-JIS 日本字符
  • ks_c_5601-1987 韩国编码
  • TIS-620 泰国编码
  • Unicode 2-4字节 已经收录136690个字符,并还在一直不断扩张中…

1. ASCII
计算机上的数据都是以二进制的形式存储的,1个字节(8比特)可以表示256种状态,英文只有26个字符,再加上一些特殊字符,使用128个就够了,计算机就可以使用127个不同字节来存储英语文字,这就是ASCII编码

最开始的时候8位中的最高位是没有用到的,后来为了表示拉丁文,将最高位用上形成扩展ASCII编码,一个字节就用满了。

2. GB2312
计算机进入中国后,无法显示中文,一个自己已经被占满了,我国重新制定了一个编码表,将扩展的第八位对应的拉丁文全部删掉,规定一个小于127的字符与原来的意义相同,当两个大于127的字符链接在一起的时候,就表示一个汉字,前面一个字节为高字节(0xA1-0xF7),后面一个字节为低字节(0xA1-0xFE),这样可以表示7000多个汉字,这种编码叫做GB2312。GB2312是对ASCII的中文扩展

3. GBK和GB18030
由于汉字的数量太大,GB2312不能满足需求,后来规定只要第一个字节大于127就固定表示一个汉字,不管后面的是不是扩展字符集里面的内容,扩展后的编码成为GBK, GBK包括了GB2312的所有内容,同时增加了近20000个新的汉字(包括繁体)和符号

4. Unicode
在Unicode出现之前,每个国家都搞自己的编码,彼此之间互不支持,带来很多麻烦,国际标标准组织提出来一个统一的编码标准:Unicode

Unicode用两个字符来表示一个字符,可以提供65535种字符,足够覆盖世界上的所有符号

5. utf-8
Unicode的出现,提供了统一的标准,但对于英文世界的国家来说,一个字节完全够用,如果使用Unicode会浪费大量空间,为了解决这个问题提出了utf-8,一种针对Unicode的可变长度字符编码,可以使用1-4个字节表示一个符号,根据不同的符号变化字节长度,当字符在ASCII编码范围时,用一个字节表示,兼用ASCII。

使用这样的编码的好处是,虽然内存汇总的数据都是Unicode,但当数据保存到磁盘或者用于网络传输时,使用utf-8会节省更多的流量和硬盘空间。

Unicode和utf-8的关系:Unicode是内存编码表示方案(规范),而utf-8是如何保存和传输Unicode的方案(实现)

2、Unicode和utf-8的关系

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个字节表示所有字符;

总结:Unicode是内存编码表示方案(规范);UTF 是为unicode编码 设计 的一种 在存储 和传输时节省空间的编码方案(实现)。

二. python2的编码

python2中字符串有两种基本类型分别是str和unicode。

str和unicode都是basestring的子类。查看源码我们发现在python2中str=bytes。
str是unicode这个字符串经过编码(utf8,gbk等)后的字节组成的序列。

Python2中默认的字符编码是ASCII码,也就是说Python在处理数据时,只要数据没有指定它的编码类型,Python默认将其当做ASCII码来进行处理,当脚本中出现了中文字符,我们知道ASCII码是不能够处理中文字符的,所以出现了编码错误。解决的办法是:在文件头部加入一行编码声明 coding:utf-8

三. python3的编码

python3也有两种数据类型:str和bytes; str类型存unicode数据,bytse类型存bytes数据,与py2比只是换了一下名字而已。

Python 3清晰地将文本和二进制数据区分开了,不会对bytes字节串进行自动解码。文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示。Python 3不会以任意隐式的方式混用str和bytes,将两者明确地区分开

四. 文件存储读取过程中的编码问题

对于文本编辑器word等软件,当我们在这些软件上编辑文字的时候,无论是什么语言的文字或符号,计算机都是无法识别的。

  • 那么在保存之前数据是通过什么形式存在内存的呢?
    是unicode数据,为什么要存unicode数据,这是因为无论世界上的任何字符它都有唯一编码对应,兼容性是最好的。

  • 当我们保存了存到磁盘上的数据又是什么呢?
    是通过某种编码方式编码的bytes字节串。比如utf8---一种可变长编码,很好的节省了空间;还可以是gbk等编码方式。

  • 在我们的文本编辑器软件都有默认的保存文件的编码方式,比如utf-8,gbk等。当我们保存的时候,这些编辑软件已经"默默地"做了编码工作。

  • 那当我们再打开这个文件时,软件又默默地给我们做了解码的工作,将数据再解码成unicode,然后就可以呈现明文给用户了!

所以,unicode是离用户更近的数据,bytes是离计算机更近的数据。

五. 编码与程序运行的关系

编写Python代码一般会用到sublime,pycharm,vim等编辑器。而代码文件的创建、保存、执行等过程就伴随着编码、解码流程。下面以pycharm为例介绍这一过程。

  1. 使用pycharm创建hello.py文件,当我们保存的的时候,hello.py文件就以pycharm默认的编码方式保存到了磁盘;
  2. 关闭文件后再打开,pycharm就再以默认的编码方式对该文件打开后读到的内容进行解码,转成unicode到内存我们就看到了我们的明文;
  3. 而如果我们点击运行按钮或者在命令行运行该文件时,Python解释器这个软件就会被调用,打开文件,然后将存储在磁盘上的bytes数据解码成unicode数据,这个过程和编辑器是一样的,不同的是解释器会再将这些unicode数据翻译成C代码再转成二进制的数据流,最后通过控制操作系统调用cpu来执行这些二进制数据,整个过程才算结束。
  4. 使用Python2需要在编码文件头加一行#--coding:utf-8--,是因为如果py2解释器去执行一个utf8编码的文件,就会以默认地ASCII去解码utf8,一旦程序中有中文或其他非ASCII字符,自然就解码错误了,所以我们在文件开头位置声明一下告诉解释器不要以默认的编码方式去解码这个文件,而是以utf8来解码。

Python3的解释器因为默认utf8编码,不存在这样的问题。 py2默认ASCII码,py3默认的utf8,可以通过如下方式查询

import sys
print(sys.getdefaultencoding())

六. linux和Windows下python编码问题

举一个例子:如果中国的软件(用的GBK编码的)出口到美国,在美国人的电脑上就会显示乱码,因为他们没有gbk编码。

  • 无论你以什么编码存储的数据 ,只要你的软件把数据从硬盘读到内存里,转成unicode来显示,就可以了。由于所有的系统、编程语言都默认支持unicode,那你的gbk软件放到美国电脑 上,加载到内存里,变成了unicode,中文就可以正常展示啦。

so ,一切都很美好,到这里,我们关于编码的学习按说就可以结束了。但是,如生活一样,美好的表面下,总是隐藏着不尽如人意。

上面案例,Windows下GBK编码之所以能在Linux utf-8的终端下显示正常,是因为到了内存里python解释器把gbk转成了unicode , 但是这只是python3,。

并不是所有的编程语言在内存里默认编码都是unicode,比如 万恶的python2 就不是, 它的默认编码是ASCII,想写中文,就必须声明文件头的coding为gbk or utf-8,。

声明之后,python2解释器仅以文件头声明的编码去解释你的代码,加载到内存后,并不会主动帮你转为unicode,也就是说,你的文件编码是utf-8,加载到内存里,你的变量字符串就也是utf-8, 这意味着什么你知道么?。。。意味着,你以utf-8编码的文件,在windows是乱码。

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

GBK / UTF-8 --> decode 解码 --> Unicode
Unicode --> encode 编码 --> GBK / UTF-8

总结

1. Linux下python2环境编码的文件,转到Windows下python2环境,出现乱码。
解决办法:将变量手动解码decode成Unicode
2. Linux下python3环境编码的文件,转到Windows下python3环境,不会出现乱码,因为python3自动解码成Unicode

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值