首页 > 代码库 > 字符编码

字符编码

1、关于Python解释器

  • 文本编辑器存取文件的原理,比如我们新建一个a.py文件
  • 打开编辑器就像打开了一个进程,在内存中运行,所以编辑器内的内容也是在内存中的具有易失性,当你点击点击保存,就是把编辑的内容刷到硬盘上了,这时候,a.py文件就相当于普通文件,都是一堆字符而已

Python解释器执行py文件的原理

  • 第一步:Python解释器首先启动,相当于启动了一个文件编辑器
  • 第二步:Python解释器去硬盘上把a.py文件再刷到内存中,
  • 第三步:Python解释器解释执行刚刚加载到内存中的a.py文件

小结:Python解释器是解释执行文件内容的,而文本编辑器只能读文件,不能执行

2、什么是字符编码

计算机只能识别高电频1和低电频0,我们该如何让我们自己认识的文件让计算机认识呢,我们必须让我们的每个字符都有一个特定数字标准来让计算机识别,这个标准就是字符编码

3、字符编码的发展史

  • 阶段一,首先是美国搞得,基于英文考虑的ASCLL:一个Bytes代表一个字符(英文字符/键盘上的所有的字符),因为1Bytes=8bit,8bit可以表示0-2**8-1种变化,即可以表示256个字符,ASCII最初只用了后七位,127个数字,已经完全能够代表键盘上所有的字符了(英文字符/键盘的所有其他字符)后来为了将拉丁文也编码进了ASCII表,将最高位也占用了
  • 阶段二:为了让计算机识别中文,中国人定制了GBK,日本人也编写了Shift_JIS,韩国也编写了。。。。
  • 阶段三:这样下去,各国由各国的标准,肯定会有冲突,在多语言的文本中,显示就会有乱码,为了解决这个问题,于是就产生了unicode,统一用2Bytes代表一个字符, 2**16-1=65535,可代表6万多个字符,因而兼容万国语言但对于通篇都是英文的文本来说,这种编码方式无疑是多了一倍的存储空间(二进制最终都是以电或者磁的方式存储到存储介质中的)于是产生了UTF-8,对英文字符只用1Bytes表示,对中文字符用3Bytes

小结:

  • nuicode:相对简单粗暴,所有字符都是2Bytes,优点是字符-->数字的转换速度快,缺点是占用空间大
  • utf-8:精准,对不同的字符用不同的长度表示,优点是节省空间,缺点是:字符->数字的转换速度慢,因为每次都需要计算出字符需要多长的Bytes才能够准确表示

内存中使用的编码是unicode,用空间换时间,因为程序都要在内存中运行,所以,内存“快”才是第一位,硬盘或者网络传输用的是utf-8,这样是为了保证数据传输稳定性,在传输过程中,还要尽量节省带宽至于utf-8的转换延迟,要小于网络延迟或硬盘I/O延迟。

内存与硬盘的I/O操作

技术分享

浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器:如果服务端encode的编码格式是utf-8, 客户端内存中收到的也是utf-8编码的二进制。

技术分享

 

小结:

无论是何种编辑器,要防止文件出现乱码(请一定注意,存放一段代码的文件也仅仅只是一个普通文件而已,此处指的是文件没有执行前,我们打开文件时出现的乱码),核心法则就是,文件以什么编码保存的,就以什么编码方式打开

 Python2和Python3的区别

  • 在Python2中有两种字符类型str和Unicode

str类型

当python解释器执行到产生字符串的代码时(例如s=‘林‘),会申请新的内存地址,然后将‘林‘encode成文件开头指定的编码格式,这已经是encode之后的结果了,所以s只能decode

1 #_*_coding:gbk_*_
2 #!/usr/bin/env python
3 
4 x=
5 # print x.encode(gbk) #报错
6 print x.decode(gbk) #结果:林

 

 重点:

 在python2中,str就是编码后的结果bytes,str=bytes,所以在python2中,unicode字符编码的结果是str/bytes

#coding:utf-8
s= #在执行时,‘林‘会被以conding:utf-8的形式保存到新的内存空间中

print repr(s) #‘\xe6\x9e\x97‘ 三个Bytes,证明确实是utf-8
print type(s) #<type ‘str‘>

s.decode(utf-8)
# s.encode(‘utf-8‘) #报错,s为编码后的结果bytes,所以只能decode

unicode类型

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

s=u
print repr(s) #u‘\u6797‘
print type(s) #<type ‘unicode‘>


# s.decode(‘utf-8‘) #报错,s为unicode,所以只能encode
s.encode(utf-8)

 

当打印到终端时

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

当程序执行时,比如

x=‘林‘

print(x) #这一步是将x指向的那块新的内存空间(非代码所在的内存空间)中的内存,打印到终端,而终端仍然是运行于内存中的,所以这打印可以理解为从内存打印到内存,即内存->内存,unicode->unicode

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

python3中的字符串与python2中的u‘字符串‘,都是unicode,所以无论如何打印都不会乱码

但是在python2中存在另外一种非unicode的字符串,此时,print x,会按照终端的编码执行x.decode(‘终端编码‘),变成unicode后,再打印,此时终端编码若与文件开头指定的编码不一致,乱码就产生了

因为:

在pycharm中(终端编码为utf-8,文件编码为utf-8,不会乱码)

而在Windows终端

在windows终端(终端编码为gbk,文件编码为utf-8,乱码产生)

  • 在Python3中也有两种字符串类型str和bytes

str是unicode

#coding:utf-8
s= #当程序执行时,无需加u,‘林‘也会被以unicode形式保存新的内存空间中,

#s可以直接encode成任意编码格式
s.encode(utf-8)
s.encode(gbk)

print(type(s)) #<class ‘str‘>

 

bytes是bytes

#coding:utf-8
s= #当程序执行时,无需加u,‘林‘也会被以unicode形式保存新的内存空间中,

#s可以直接encode成任意编码格式
s1=s.encode(utf-8)
s2=s.encode(gbk)



print(s) #
print(s1) #b‘\xe6\x9e\x97‘ 在python3中,是什么就打印什么
print(s2) #b‘\xc1\xd6‘ 同上

print(type(s)) #<class ‘str‘>
print(type(s1)) #<class ‘bytes‘>
print(type(s2)) #<class ‘bytes‘>

 

字符编码