gbk编码在线转换_一站式解读彻底搞懂Python编码

 Python的编码问题,有一个完整的体系。如果不从整体上进行讨论,总是云里雾里的。

从敲代码到屏幕看到字符,涉及好几个关键的环节。每一个环节对于字符的正常输出都有很大的影响。


涉及到的环节有:输入代码并存储 -> Python解释器加载文件 -> 字符编码转换 -> 字符输出显示
本文以python2来讨论这些环节。

01

输入代码并存储

为了方便讨论,这里我先取一个词,叫做存储编码。存储编码是将录入的代码字符存储起来,用于后续处理而使用的一个编码格式。
一段python代码的运行,可以分为两种场景:
1、 交互执行
交互执行是在终端上用户输入,python解释器即时执行的模式。
交互执行的环境有Windows的命令行和Linux的终端等。两者的区别就在于分别使用的默认编码不一样。这里的默认编码指的是存储代码的默认编码和显示字符的默认编码。Windows的命令行默认的是GBK,而Linux默认的是UTF-8。我们常用的Sublime Text软件默认的是UTF-8,而python自带的命令行和Windows的一样。

Win控制台:

ff1e31dec210b7ebd8ed30868095907b.png

Linux终端:

e2a3e3d86342d3fc274a2da834048397.png

可以看到,因为采用了不同的默认编码,所以可以看到直接查看b的变量的编码值长度和字节序列都是不一样的。注意,这里不要用print来输出b,那样看到的不是b存储的编码字节序列,而是输出的字符。

不管是GBK还是UTF-8,都是兼容了ASCII的,所以这里你使用英文字符串是看不到这个效果的。

而字符串前面加了u的,不管是win还是Linux,存储的都是unicode对象。

交互执行的方式,用户输入的str字符串的编码是以控制台/终端默认的编码格式进行编码并存储在内存中的。而unicode字符串则是以unicode对象的形式存储在内存的,unicode对象用于python各种编码相互转换的中间编码格式,我们不用在意内部的具体编码格式。通过这个中间编码格式,可以方便的在各种编码之间转换。

2、 文件执行

文件执行是将代码全部保存在文件,由python解释器一次性加载到内存,然后逐行解释执行的模式。

文件执行的方式需要事先将代码文件存储起来,所以需要指定一种文件编码格式,这里的格式就是存储编码。存储编码是对所有代码包含注释都起作用的。所以文件的存储编码和第一行的文件编码声明没有关系,和字符串前加不加u也没有任何关系。

UTF-8文件存储

7d000c8540cf9c9d476b8d6daf73c058.png

f3ddf523ff9097fd8215d8575506f907.png6e5ad237894c2e41d3c44de2629c49d3.pngedf5a6d6d3ec7eae95cb0a20795a43fe.png

GBK文件存储

7d000c8540cf9c9d476b8d6daf73c058.png

9bdbbc74a2e4d85f8aa76e87d94c9a8a.png

6e5ad237894c2e41d3c44de2629c49d3.png

f9a463460b71c65d630d47d13a490412.png

02

Python解释器加载文件

Python解释器加载文件,即将存储在磁盘的py文件加载到内存。因为py文件是文本文件,所以文件内存储的是字符类型的数据。字符类型数据就涉及到编码的问题。存储的时候是以一种编码格式存储的,那么读取的时候也要按同样的编码格式读取,否则会出错。

但是就一段文本文件的字节序列并不能判断出来文本文件存储时使用的编码,所以py文件中在第一行/第二行用一段注释来声明文件存储时使用的编码。这里我将之称之为文件编码声明。

如果代码文件的存储编码和文件编码声明指定的编码不一致,则会报错。如果没有指定,一般情况下python解释器会报错,告诉你没有声明文件使用的编码。但是一些解释器可能只是提醒,但是不会报错,就会用默认的ASCII编码来读取文件。

存储编码为UTF-8,文件编码声明为GBK。报错:

SyntaxError: 'gbk' codec can't decode bytes in position 7-8: illegal multibyte sequence

此报错的意思是,python按照声明的gbk编码(gbk存储编码是多字节序列来支持中文的)去读取文件。python会按照多字节序列的规则去读取文件字节序列。然而实际存储的是utf-8编码,utf-8编码的格式和gbk编码格式并不兼容,所以按照gbk来读取序列就会发现非法的gbk字节序列值,因此报了illegal multibyte sequence(非法多字节序列)的错误。

存储编码为GBK,声明编码为UTF-8。报错:

SyntaxError: (unicode error) 'utf8' codec can't decode byte 0xd6 in position 0: invalid continuation byte

此报错的意思是,python按照声明的utf-8编码去读取文件。当读取到字符串的时候,发现字节序列的编码值不在utf-8的字符编码值范围内,所以提示后续连续的字节序列是无效的字节。

总结:报错时提示什么编码就说明声明的是此编码,而实际存储的数据的编码格式并不是声明的这个。

03

字符编码转换

Python内部使用Unicode对象来处理字符串。

1. 字节序列str

使用type函数将字符串输入,输出来是的字符串就是str字节序列对象。此对象是基于GBK编码的字节序列。GBK字节序列一般是这样的: '\xd6\xd0\xb9\xfa',字节序列是\x即十六进制的序列。UTF-8的字节序列一般是这样的:'\xe4\xb8\xad\xe5\x9b\xbd'。两者都对应字符串‘中国’。

2. unicode对象

使用type函数将字符串输入,输出来是的字符串就是unicode对象。unicode对象是用u‘‘包起来的字符串。Unicode的字节序列是这样的:u'\u4e2d\u56fd'。

3. 编码encode

编码是将unicode对象转为字节序列str。编码是将人类易于识别的格式变成二进制的字节,让存储和处理更高效。编码相当于将散开的东西打包给机器存储、运输、加工和输出显示等。已经是字节序列的str类型,则不能再encode了。编码时要指定一个编码格式,将unicode对象按照这个编码格式转为对应格式的二进制字节序列。

4. 解码decode

解码是将字节序列str转为unicode对象。解码是将已打包的东西解开来看的。已经是unicode对象则不能再解码了。解码需要指定一个编码,是要按照已经被编码的格式解码,所以指定的编码格式要正确。

5. 乱码

字符串的编码格式和显示指定的编码格式不一致,但是指定的显示的编码格式刚好能映射字符串的编码值,所以解析为了不是预期的字符。

5aa5624d0f977d9ab26d33ce85fd1f7b.png

b10656fd66d362363179d52576b4ec0e.png

6. 编码报错

前面讨论的是文件读取时候的编码报错,而这里说的是转码过程中的编码报错,这也是最常见的编码报错。

1 已经是str,再encode

7e5f5a0bcf6a75480ea193e55975d0d7.png

2 已经是unicode对象,再decode

8508f9e0cf9ad47b3af505633428cdd2.png

3 解码时指定的编码格式和存储的编码格式不一致,且指定编码格式和存储的编码格式不兼容。

兼容的情况,都能够解码为正确的unicode对象。

f889cc933d39b4842cdc85a3a8c2b7aa.png

完全不兼容的情况,直接报错。

07d54ddebf7269fc6ff13a9745e23085.png

部分兼容,解码时发现字节序列的编码值在iso-8859-1范围内,但是解出来得到的unicode对象并不是通用的格式,而是基于十六进制的unicode对象。此对象并不能直接编码为其他的编码格式的字节序列。所以后面的print报错了。提示是在\xd6字节处发现不兼容而报错的。假如字节序列的编码值刚好在gbk的范围内,那么就不会报错了,而是出现乱码,结果打印出来的就不是’中国’了。

021b0ac65e2bb4e39bcd2d590bb6fc03.png

我们最后将结果通过一系列编码解码还原为了最初的gbk编码字节序列了。这样打印也就正常了(win控制台默认是gbk的)。

虽然将gbk的字符串解码为iso-8859-1在这里没有报错,并不代表所有字符都可以这样解码而不报错哦。

为了能够让编码之间能够顺利的转换,解码时要用正确的编码解码,然后就可以用unicode对象做中转进行编码转换了。能够相互转换的前提是两个编码是都可以表示此字符串的。字符串’中国’在ascii和iso-8859-1是不存在的,所以无论如何都转不过去的,但是ascii和iso-5589-1是可以转到gbk和utf-8的。

4 编码时字符串的字节编码值不在目标编码格式的范围内

08532ce296e2141ad30f891fe35f28f9.png

我们尝试将GBK编码的字符串解码为unicode对象,然后再编码为iso-8859-1(别名latin-1)和ASCII,结果都报错了。

7. 兼容

本文说的兼容指的是广义上的兼容,即出现乱码的编码值在两个编码格式中都存在对应的编码值,但是此编码值对应的字符不一定相同。字符不同即能将编码值映射到字符,但不是预期的字符。如果编码值相同,对应的字符也相同,那就是狭义上的字符集兼容。比如GBK兼容GB2312、GB2312兼容ASCII等。

4a22d5e34fc80a8880be02ec09b141c0.png

我们再尝试将gbk编码解码后编码为gb2312,结果是可以正常编码的,而且编码为gb2312的字节序列和gbk的字节序列是一样的,这说明字符串’中国’在gb2312和gbk两个编码格式中是兼容的。

04

字符输出显示

输出编码即打印输出的编码格式或存储文件的格式。Win控制台默认是GBK编码,Linux终端默认的是UTF-8编码。文件则是在保存文件时指定的编码。如果传递给输出的编码和显示终端的默认编码不一致则会出现乱码或报错。如果传递给输出设备的编码在默认编码的范围内,则会出现乱码。如果不在默认编码范围内,则会报编码错误。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值