python 基础 字符编码

时间:2023-01-04 15:43:17

    编码基础 

  • ASCII 占1个字节,只支持英文
  • GB2312 占2个字节,支持6700+汉字
  • GBK GB2312的升级版,支持21000+汉字
  • Shift-JIS 日本字符
  • ks_c_5601-1987 韩国编码
  • TIS-620 泰国编码

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

Unicode 2-4字节 已经收录136690个字符,并还在一直不断扩张中...

Unicode 起到了2个作用:

  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编码 设计 的一种 在存储 和传输时节省空间的编码方案。

字符在硬盘上的存储都是 以二进制的方式存储的

编码的转换 

 

虽然国际语言是英语 ,但大家在自己的国家依然说自已的语言,不过出了国, 你就得会英语 编码也一样,虽然有了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  代码的执行过程 

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

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

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

代码如下所示

#coding:utf-8
s = "路飞学成"
print(s)

 在windows 下面执行如下图所示

python 基础 字符编码

使用python3 在  windows 下面执行上述代码是正常的

正常执行原因:  在python3里   上面的utf-8编码之所以能在windows gbk的终端下显示正常,是因为到了内存里python解释器把utf-8转成了unicode 

在python2 执行如下代码文件 py2_encode 

代码如下所示 

#coding:utf-8
s = "路飞学成"
print(s)

python 基础 字符编码

使用 python2 ,在windows 下面执行是乱码的

乱码原因:python2解释器仅以文件头声明的编码去解释你的代码,加载到内存后,并不会主动帮你转为unicode,也就是说,你的文件编码是utf-8,加载到内存里,你的变量字符串就也是utf-8, 这意味着什么你知道么?。。。意味着,你以utf-8编码的文件,在windows是乱码。要想使文件正常显示 需要做到以下两个方面 1、字符串 以GBK格式显示,2、字符串是unicode 编码 

python3 自动把文件转换成unicode 编码   主要是进行了 decode 解码,和encode 编码

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

实例演示:

decode 解码

#coding:utf-8
s = "路飞学成"
print(s)
s2 = s.decode('utf-8') 
print(s2) # s2 以Unicode 格式显示,会正常显示 print(type(s2))

python 基础 字符编码

 encode 编码

#coding:utf-8
s = "路飞学成"
print(s)
s2 = s.decode('utf-8')
print(s2)
print(type(s2))
print("==================")
s3 = s2.encode('GBK')  # 将unicode 编码成gbk
print(s3)
print(type(s3))  # str

 

代码执行如下所示

python 基础 字符编码

 

Python bytes类型

Python2 中 

>>> s = "路飞"
>>> s
'\xc2\xb7\xb7\xc9'

  但直接调用变量s,看到的却是一个个的16进制表示的二进制字节,我们怎么称呼这样的数据呢?直接叫二进制么?也可以, 但相比于010101,这个数据串在表示形式上又把2进制转成了16进制来表示,这是为什么呢? 哈,为的就是让人们看起来更可读。我们称之为bytes类型,即字节类型, 它把8个二进制一组称为一个byte,用16进制来表示, 嗯 ,是的,在python2里,bytes == str , 其实就是一回事。 python2里还有个单独的类型是unicode , 把字符串解码后,就会变成unicode

>>> s = "路飞"
>>> s
'\xc2\xb7\xb7\xc9'   #GBK 格式
>>> s.decode('GBK')
u'\u8def\u98de'   #在unicode编码表里对应的位置
>>> print(s.decode('GBK'))
路飞 #  #unicode 格式的字符

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

在python3 中  除了把字符串的编码改成了unicode, 还把str 和bytes 做了明确区分, str 就是unicode格式的字符, bytes就是单纯二进制啦。

>>> s = "路飞"
>>> s
'路飞'
>>> print(type(s))
<class 'str'>    # python3 中str  等于 py2 中的unicode 类型
>>> s.encode("GBK")
b'\xc2\xb7\xb7\xc9'  # bytes 类型

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

python 编码常见排错方式 

  • Python解释器的默认编码
  • Python源文件文件编码
  • Terminal使用的编码
  • 操作系统的语言设置 掌握了编码之前的关系后,挨个排错就好啦