Python字符编码

字符初期

(1)计算机只能处理数字,如果处理文本,需要把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255(二进制11111111=十进制255),如果需要表示更大的整数,需要更多的字节,比如2个字节可以表示最大整数65535,4个字节最大整数4294967295
Python字符编码
一个字节8个比特(bit)!2个字节就是16比特,4个字节就是32字节!

0~65535=65536(2^16-1+1) >>(计算机从0开始计算,0也算一个存储单位,所以要加上)

ASCII编码


(2)由于计算机是美国发明的,因此最早只有127个字符被编码到计算机中,也就是大小写英文字母,数字和一些符号,这个编码表被称为**ASCII**编码,比如大写字母Z的编码是90,小写字母a的编码是97.


GB2312编码

(3)处理中文显然一个字节是不够的,值少需要两个字节,还不能和ASCII编码冲突,所以中国制定GB2312编码,


(4)全世界有几百种语言,比如:

日本编码

Shift_JIS

每个国家都有自己的标准,就不可避免的出现冲突,结果就是现实乱码!

Python字符编码
乱码后
Python字符编码

Unicode编码

(5)字符编码Unicode出世了,Unicode把所有语言都统一到一个套编码里,这样不在有乱码问题了!!
 Unicode也在不断的发展,但最常用的就是2个字节表示一个字符(如果非常偏僻的字符,需要4个字节),现代操作系统和大多数编程语言都直接支持Unicode.

ASCII/Unicode的区别?

ASCII

ASCII编码是1个字节

Unicode

Unicode编码通常是2个字节

A用ASCII是十进制的65,二进制是01000001;
0用ASCII编码是十进制的48,二进制是00110000,注意字符'0'整数0是不同的;
 汉字已经超出了ASCII编码的范围,用Unicode编码是十进制的20013,二进制的01001110 00101101
 如果把ASCII编码中的A用Unicode编码表示,只需要在前面补0即可,因此A的Unicode编码是00000000 01000001

说明

统一成Unicode编码,乱码问题消失,但是如果写的文本英文占有大部分,Unicode要比ASCII存储空间多一倍!在存储传输上很不划算!

UTF-8编码

为节约存储和传输上的不划算,出现了把Unicode编码转化为"可变长编码"的**UTF-8**编码,把一个Unicode字符根据不同的数字大小编程1-6个字节,常用的英文编码成1个字节.汉字一般是3个字节,只有很生僻的字符才编码为4-6个字节,现在如果你文本中含有大量英文字符,用UTF-8会节省很多空间.
Python字符编码
在上图可以发现,UTF-8的一个额外好处,就是ASCII编码实际可以被看成UTF-8的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8下继续工作!

小结

计算机系统通用的字符编码工作方式:
1)在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者传输的时候,转换为UTF-8编码

2)用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候在把Unicode转换为UTF-8保存到文件
Python字符编码

3)浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器
Python字符编码
所以在看网页源码的时候会有类似<meta charset="UTF-8" />的信息,表示网页用的是UTF-8编码.

Python的字符串

(1)在python3版本中,字符串是以Unicode编码的,python支持多语言,如

>>>print("shuai的帅")
shuai的帅

(2)对于单个字符的编码,python还提供了两个函数:
**ord()函数**获取字符的整数表示;
**chr()函数**把编码转换为对应的字符;

>>> ord('S')
83
>>> ord('帅')
24069
>>> chr(24069)
'帅'
>>> chr(83)
'S'

(3)如果知道字符的整数编码,还可以用十六进制写str:

解释说明:

str=string >>字符类型(字符串)

>>>"\u4e2d\u6587"
'中文'

(4)由于python的字符类型时str内存中以Unicode表示,一个字符对应多个字节,如果需要在网络传输,或保存到磁盘上,就需要把str变为以字节为单位的bytes

name = b"shuai"

要注意区分shuaib"shuai",前者是str,后者虽然内容显示的和前者一样,但是bytes的每个字符都只占用一个字节.
以3Unicode表示的str通过encode()方法可以编码为指定的bytes,例如:

>>>'zhang'.encode('ascii')
b'zhang'

>>>'张'.encode('utf-8')
b'\xe5\xbc\xa0'

>>>'张'.encode('ascii')
---------------------------------------------------------------------------
#报错:
UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-20-e1fb28eb976f> in <module>
----> 1 '张'.encode('ascii')

UnicodeEncodeError: 'ascii' codec can't encode character '\u5f20' in position 0: ordinal not in range(128)

说明

纯英文的str可以使用ASCII编码为bytes,内容是一样的,含有中文的str可以用UTF-8编码为bytes,还有中文的str无法用ASCII编码,因为中文编码范围超过了ASCII编码的范围,python会像上面例子一样报错

(5)在bytes中,如果我们从网络或磁盘上读取了字节流,那么读取到的数据就是bytes,要把bytes变为str,就要使用**decode()方法**

>>>b'shuai'.decode('ascii')
'shuai'

>>>b'\xe5\xbc\xa0'.decode('utf-8')
'张'

如果bytes中包含无法解码的字节, **decode()方法**会报错

>>>b'\xe5\xbcs\xa0'.decode('utf-8')

---------------------------------------------------------------------------
#报错
UnicodeDecodeError                        Traceback (most recent call last)
<ipython-input-24-9f762c468f58> in <module>
----> 1 b'\xe5\xbcs\xa0'.decode('utf-8')

UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 0-1: invalid continuation byte

(6)如果bytes中只有一小部分无效字节,可以传入errors='ignore'忽略报错字节

>>>'大神'.encode('utf-8')   #正常
b'\xe5\xa4\xa7\xe7\xa5\x9e' #正常输出

>>>b'\xe5\xa4\xa7\xe7\x2a282\x922edd'.decode('utf-8',errors='ignore') #使用errors='ignore',并改错编码
'大*2822edd'  #有效字节继续输出

>>>b'\xe5\xa4\xa7\xe7\xasssss5\x9e'.decode('utf-8') #不加errors='ignore'
---------------------------------------------------------------------------
#报错
  File "<ipython-input-32-362b4cfd219c>", line 1
    b'\xe5\xa4\xa7\xe7\xasssss5\x9e'.decode('utf-8')
                                                    ^
SyntaxError: (value error) invalid \x escape at position 16

(7)要计算str包含多少个字节,可以使用**len()函数**

>>>len('shuai')
5

>>>len('帅')
1

**len()函数**计算的是str的字符数,如果换成bytes,len()函数就计算字节数:

>>> len(b'ABC')
3
>>> len(b'\xe4\xb8\xad\xe6\x96\x87')
6
>>> len('中文'.encode('utf-8'))
6

说明

一个中文字符经过UTF-8编码后通常会占用3个字节,而1个英文字符只占用一个字节.

在操作字符串时,经常遇到strbytes的相互转换,为了避免乱码问题,应当始终坚持使用UTF-8编码对strbytes进行转换.

(8)如何让python自动保存为UTF-8编码呢

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

说明

第一行告诉系统这是一个python可执行程序
第二行告诉python解释器使用UTF-8编码读取源代码

即便声明了,也要在使用编辑器的时候,把编辑器的编码格式改为相对应的字符集!

格式化

(1)什么是格式化输出?
有时会输出如以下:
**你好XXX,我是XXX公司的我叫XXXX,**这里面的XXX就是要根据变量的变化而变化,需要一种简便的格式化字符串的方式来搞定!

(2)在python中采用的格式化方式是**%**来实现的.

>>> 'Hello, %s' % 'world'
'Hello, world'
>>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
'Hi, Michael, you have $1000000.'

%运算符就是用来格式化字符串的,在字符串内部,%s表示用字符串代替,%d表示用整数代替,有几个%?,后面就更几个比变量或者值,顺序要对应好,如果只有一个%?,括号可以省略

占位符 替换内容
%d 整数
%f 浮点数
%s 字符串
%x 十六进制整数

格式化整数和浮点数还可以指定是否补0和整数与小数的位数
以下是指定整数和小数的位数
Python字符编码


以下是指定是否补0
Python字符编码

说明

如果你不知道自己该用什么,那么就使用万能的**%s**,它会把任何数据类型转换成字符串

>>> 'Age: %s. Gender: %s' % (25, True)
'Age: 25. Gender: True'

(3)format()方法
format()方法它会用传入的参数依次替换字符串的占位符{0},{1},{2}…,不过这种范式写起来要比%麻烦~

>>> 'Hi, {0}, 成绩提升了 {1:.1f}%'.format('小黑', 13.12225)
'Hi, 小黑, 成绩提升了 13.1%'

Python字符编码