欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python字符编码详解

程序员文章站 2023-11-03 23:32:34
本文详细讲解字符编码的相关知识,包括字符编码的发展历程,字符编码的使用,在python中字符编码的应用 首先要明确:计算机中的所有数据,不论是文字、图片、视频、还是音频文件,本质上最终都是按照类似 01010101 的二进制存储的 拓展1:什么是编码,解码? 1.信息的两种状态: 1)明文状态:类似 ......

本文详细讲解字符编码的相关知识,包括字符编码的发展历程,字符编码的使用,在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的映射表

 

完毕,呵呵呵呵