Python字符编码详解
本文详细讲解字符编码的相关知识,包括字符编码的发展历程,字符编码的使用,在python中字符编码的应用
首先要明确:计算机中的所有数据,不论是文字、图片、视频、还是音频文件,本质上最终都是按照类似 01010101 的二进制存储的
拓展1:什么是编码,解码?
1.信息的两种状态:
1)明文状态:类似显示器上能看到的消息,内容等,存储在内存中,是处于运行状态的信息,一般是用Unicode万国码存储的数据流(或者叫信息流,字节流等)
2)文件状态:类似硬盘文本文件中存储的数据或者信息,相对来说是处于静止的状态,存储方式为二进制0101
3)人可以看懂显示器上的明文,计算机可以看懂文本中的二进制数据
4)将明文(内存中的信息流)从内存中保存到硬盘文件中的过程需要用到“编码”操作,将文本内容从硬盘读到内存中的过程需要用到“解码”操作
5)“编码”就是我们保存文件的过程,解码”就是我们打开文件的过程,这两个过程是互逆的
拓展2:字符与字节
1.字符
显示器可以看到的汉字或英文就是字符
不同编码下一个字符占用的内存或磁盘空间不同
2.字节(B,Byte)
是计算机存储的最小单位,一字节等于八位
是计算机编程语言中的数据类型和语言字符。
3.位(b,bit,比特)
数据传输的最小单位
4.B与bit
数据存储是以“字节”(Byte)为单位,数据传输大多是以“位”(bit)为单位,
一个位就代表一个0或1(即二进制),每8个位组成一个字节
5.B与iB
1)数据的存储与传输
数据存储是以10进制表示,数据传输是以2进制表示的,所以1KB不等于1000B。
1KiB(Kilobyte)=1000byte 1MiB(Megabyte)=1000000byte 1KB(Kibibyte)=1024byte 1MB(Mebibyte)=1048576byte
2)硬盘标称容量与实际容量
硬盘生产商是以十进制,GiB(即10的3次方=1000,如1MiB=1000KB)计算的,
而电脑是以2进制,GB(即2的10次方, 如1MB=1024KB)计算的
但是国内用户一般理解为1MiB=1M=1024 KB, 所以为了便于中文化的理解,翻译MiB为MB也是可以的。
3)单位转换
1B=1Byte=8bit 1KB=1024B 1MB=1024KB 1GB=1024MB 1TB=1024GB 1PB=1024TB 1EB=1024PB 1ZB=1024EB 1YB=1024ZB 1BB=1024YB
======== 分割线 =======
1.常见的编码格式
1.1.ASCII码:最早的字符编码
1)全称:美国标准信息交换代码,American Standard Code for Information Interchange
2)设计初衷:为了与计算进行交互设计出ASCII码,是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言
3)设计原理:计算机上的数据都是以二进制的形式存储的,1个字节(8比特)可以表示256种状态,英文只有26个字符,再加上一些特殊字符,使用128个就够了,计算机就可以使用127个不同字节来存储英语文字,就是ASCII编码
最开始的时候8位中的最高位是没有用到的,后来为了表示拉丁文,将最高位用上形成扩展ASCII编码,一个字节就用满了。
4)编码规定:每个字符(英文字符)最多只能用一个字节(8 位bit)来表示,所有字符都各占1个字节
即:2**8 = 256-1,所以,ASCII码最多只能表示 255 个符号。
1.2.GB2312 (1981)(关于中文的处理)
1)设计初衷:计算机进入中国后,无法显示中文,现有的ASCII已经被占满了无法编码中文,于是制定GB2312,
2)设计原理:将ASCII码扩展的第八位对应的拉丁文全部删掉,规定一个小于127的字符与原来的意义相同,当两个大于127的字符链接在一起的时候,就表示一个汉字,前面一个字节为高字节(0xA1-0xF7),后面一个字节为低字节(0xA1-0xFE),这样可以表示7445个中文字符
3)编码特点:收录7445个中文字符,6763个汉字和682个其他符号,GB2312是对ASCII的中文扩展,是支持中文的第一张表
1.3.GBK1.0 (1995) (GBK)
1)设计初衷:由于汉字的数量太大,GB2312不能满足需求
2)设计原理:规定只要第一个字节大于127就固定表示一个汉字,不管后面的是不是扩展字符集里面的内容,扩展后的编码为GBK1.0版本
3)编码特点:GBK包括了GB2312的所有内容,收录21886个中文字符(包括繁体)和符号
4)编码规定:1个中文字符占2个字节
1.4.GB18030 (2000)
1)设计初衷:是为了取代GBK1.0的正式国家标准,
2)设计原理:略
3)编码特点:该标准收录27484个汉字,和其他藏文,蒙文,*文,繁体,日文,朝鲜语等主要的少数名族文字,GB18030相对GBK增加的字符普通人很难用到
4)编码规定:1个中文字符占2个字节
1.5.Unicode万国码:统一的字符编码
1)其他名称:也叫统一码,单一码
2)设计初衷:由于ASCII码无法表示世界上所有国家和地区的文字和符号,每个国家都搞自己的编码,彼此之间互不支持,带来很多麻烦,所以设计出Unicode
3)编码特点:可以提供65535种字符,支持了全球各个国家的语言编码,且包含了与所有国家编码的映射关系
4)编码规定:所有的文字和符号最少由2个字节(16位)来表示,可能更多,一般是2-4个字节
即:2**16 = 65535 = 存一个字符,统一占用2个字节
1.6.UTF-8字符集
1)设计初衷:由于Unicode使用2-4个字节,对于英文世界的国家来说,一个字节完全够用,使用Unicode会造成空间浪费
2)设计原理:对Unicode进行优化产生一种可变长的字符编码集,根据不同的符号变化字节长度,当字符在ASCII编码范围时,用一个字节表示,兼用ASCII,在存储和传输时更加节省空间
3)编码规定:英文字符用ASCII码来存,一个英文字符占1个字节,一个欧洲语言字符占2个字节,1个中文字符占3个字节
4)其他不同的Unicode扩展集:
utf-16:一个字符占2个字节或2个以上,可以存2的16次方,共65535个字符
utf-32:一个字符占4个字节
5)Unicode和utf-8的关系:Unicode是内存编码方案(规范标准),而utf-8是字符集,是保存和传输Unicode的是实现方式
一般不直接用Unicode,而是用UTF-8等字符编码
注意: 1)以上几种编码,后面的编码兼容前面的标准,在这些编码中,英文和中文可以统一处理。 unicode向下兼容gb2312 , gbk 2)区分中文编码的方法是高字节的最高位不为0。 3)按照程序员的习惯,GB2312、GBK1.0到GB18030都属于双字节字符集 (DBCS)。 4)中国规定:进入中国的软件必须支持GBK,PC平台要求必须能支持GB18030,嵌入式产品,如手机,MP3等不做要求,只需要支持GB2312即可 5)无论以何种编码在内存里显示字符,存在硬盘上后都是二进制编码 6)在硬盘上以何种编码存的数据,必须以原来的编码读取,否则会乱码
1.6.其他地区的编码字符集
BIG5 (1984):*设计,13053个繁体中文
Shift-JIS,日本字符
ks_c_5601(1987),韩国字符
TIS-620,泰国编码
1.7.ANSI编码(American National Standards Institute美国国家标准学会)
1)不同的国家和地区制定了不同的标准,由此产生了 GB2312、GBK、Big5、Shift_JIS 等各自的编码标准。这些使用 1 至 4 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。
2)在简体中文Windows操作系统中,ANSI 编码代表 GBK 编码;
3)在日文Windows操作系统中,ANSI 编码代表 Shift_JIS 编码。
4)不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。 当然对于ANSI编码而言,0x00~0x7F之间的字符,依旧是1个字节代表1个字符。这一点是ANSI编码与Unicode编码之间最大也最明显的区别。
总结:
1)字符编码的发展:
ASCII -->GB2312 ->GBK1.0(GBK)-->GB18030 ASCII -->unicode -->utf-8/utf-16
2)不同字符编码占用的磁盘空间大小
1)ASCII码中:一个英文字符(拉丁文)占1个字节,8位,不能存中文,所以出了Unicode 2)GBK中:一个中文字符占用2个字节,1个英文字符占用1个字节 3)unicode中:默认所有中英文字符都占2个字节,16位, 4)utf-8中:一个中文字符占用3个字节,一个英文字符默认占1个字节,8位
2.字符编码的使用
2.1.Python解释器中的字符编码的使用
Python解释器在加载 .py文件中的代码时,需要使用指定的字符编码将内容进行转换为0101这种二进制代码,交付给CPU处理
Python2.x解释器默认编码是ASCII码,不支持中文,要使用中文,需提前申明字符编码
Python3.x解释器默认编码是unicode,支持中文,不需要申明字符编码
Python2.7支持中文的方法:
1)编辑py程序msg.py,在第一行申明需要使用的字符编码
vim msg.py ------------------------- # -*- coding:utf-8 -*- # 放在第一行; # encoding:utf-8 # 放在第一行; # coding:utf-8 # 放在第一行; msg = "今天天气真不错" print(msg) ------------------------- python msg.py --->今天天气真不错
也可以用这种:
#!/usr/bin/env python # -*- coding: utf-8 -*-
2)变量值前加个字母“u”,代表用Unicode显示
vim msg.py ------------------------- msg = u"今天天气真不错" print(msg) ------------------------- python msg.py --->今天天气真不错
2.2.系统中编码的使用:
1)中文Windows默认编码:GBK(GBK1.0)
切换字符编码为GBK的windows命令:
chcp 936
2)Mac和Linux默认编码:UTF-8
3)打印系统默认编码
import sys print(sys.getdefaultencoding())
3.字符编码转换
3.1.Python2中的string编码
1)在Python2中,字符串可以存成两种类型:str和unicode,他们在内存中的存储方式不同,但都可以直接打印到屏幕上
str存储byte字节数据,用<type 'str'>表示,存入的是二进制bytes的str类型,打印到屏幕时会自动转为Unicode,所以可以打印中文,也可以手动转换为Unicode打印到屏幕
unicode存储unicode数据,用<type 'unicode'>表示,直接保存成Unicode数据,可以直接打印内存中的Unicode数据到屏幕,也可以编码为str字符串打印出来
str1:UTF-8 --> str1.decode("utf-8") -->str1-2:Unicode --> str1-2.encode("gbk")-->str1-2:GBK str2:GBK --> str2.decode("gbk") -->str2-2:Unicode --> str2-2.encode("utf-8") -->str2-2:UTF-8
2)两种类型可以通过编码解码进行相互转换,也可以进行字符串拼接(bytes数据会自动转码为Unicode)
3)只要数据全部是ASCII,自动转换就正常,否则会出现乱码,出现UnicodeDecodeError 的错误
Python2编码让程序在处理 ASCII 的时候更加简单,代价就是在处理非 ASCII 的时候将会失败
实例演示1:
[root@zssrv ~]# python2 ---------------------------- str1='中国hello123' print type(str1) # <type 'str'>,存入的是str类型 print repr(str1) # '\xe4\xb8\xad\xe5\x9b\xbdhello123',内存中存储的二进制bytes数据 print str1 # 中国hello123,打印到屏幕时会自动转为Unicode,所以可以打印中文 a = str1.decode('utf8') # str类型也就是二进制bytes,手动解码成Unicode读出来 print type(a) # <type 'unicode'>,转换为了Unicode print repr(a) # u'\u4e2d\u56fdhello123',内存中存储的Unicode数据 print a # 中国hello123,手动转换成的a是Unicode所以可以打印中文 a2 = str1.decode('gbk') # 但如果用错误的编码解析,就会报错 # --->UnicodeDecodeError: 'gbk' codec can't decode bytes in position 2-3: illegal multibyte sequence str2=u'你好hello123' print type(str2) # <type 'unicode'>,直接保存成了Unicode数据 print str2 # 你好hello123,直接打印内存中的Unicode数据 print repr(str2) # u'\u4f60\u597dhello123',内存中存储的Unicode数据 b = str2.encode('utf-8') # Unicode类型的,可以编码为str读出来 print b # 你好hello123 print type(b) # <type 'str'> print repr(b) # '\xe4\xbd\xa0\xe5\xa5\xbdhello123' ---------------------------
实例演示2:字符串拼接
print (u"hello"+"world") # hello中国 print ("hello"+u"中国") # hello中国 print (u"hello"+"中国") --->UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
3.2.Python3中的string编码
1)在Python3中,字符串有两种数据类型:str(unicode)和bytes,但内存中都表示为Unicode,可以直接打印到屏幕
str类型存unicode数据,用<class 'str'>表示,使用”\uxxxx“显示,也就是内存中的文本数据流
bytse类型存bytes字节数据,用<class 'bytes'>表示,使用b’\uxxxx’这种二进制格式显示,也就是硬盘文本文件中的内容
2)在Python命令行中,Unicode字符会默认的转换成可显示的字符串格式,而不会显示其本身的二进制码。
3)Python 3最重要的新特性之一是对文本和二进制数据作了更为清晰的区分,不再会对bytes字节串进行自动解码。
4)不能拼接字符串和字节包,不能在字节包里搜索字符串(反之亦然),不能将字符串传入参数为字节包的函数(反之亦然)。
实例演示:Python3中
import json str3 = '你好' print(str3) # 你好,可以直接打印字符串 print(type(str3)) # <class 'str'>,在内存中保存成Unicode数据 print(json.dumps(str3)) # "\u4f60\u597d" c = str3.encode('utf8') # 可以手动编码为bytes类型,二进制数据 print(c) # b'\xe4\xbd\xa0\xe5\xa5\xbd',直接打印二进制数据,而不是字符内容 print(type(c)) # <class 'bytes'> u = c.decode('utf8') # 再次用utf-8解码为str字符串类型(Unicode数据) print(u) # 你好 print(type(u)) # <class 'str'>,查看是Unicode数据 print(json.dumps(u)) # "\u4f60\u597d" str4 = u'你好' print(str4) # 你好,可以直接打印,没必要前面加u print(type(str4)) # <class 'str'> print(json.dumps(str4)) # "\u4f60\u597d"
实例演示:字符串拼接,不同类型,肯定会报错
print(b'hello'+'world') # TypeError: can't concat str to bytes
注意:
1)在Python 2中,print是一个语句(statement);在Python 3中变成了函数(function)。
2)无论py2,还是py3,与明文直接对应的就是unicode数据,打印unicode数据就会显示相应的明文(包括英文和中文)
3)在内存中的unicode,存到硬盘上或网络传输需要转成gbk/utf-8(自动转)
4)音视频文件是用二进制bytes字节数据保存的
5)Python3里只有Unicode才会打印中文,s.encode("gbk")不会打印中文(不去编码表里找),而是显示bytes数据
通过这种方式就是想告诉别人:py3里想要看到字符,必须是Unicode,其他的编码一律按bytes格式展示
遇到乱码问题的思路:
1)Python解释器的默认编码(py2,py3)
2)Python源文件文件编码(申明的编码utf-8,gbk)
3)Terminal使用的编码(cmd等)与py文件的不匹配
4)操作系统的语言设置(windows,linux,mac等)
常用的编辑器默认编码
EmEditor GB2312 pycharm unicode notepad++ utf-8
参考文章:
python 之路,致那些年,我们依然没搞明白的编码
py编码终极版
字符串相关
unicode与gbk的映射表
完毕,呵呵呵呵