Python字符编码详解

Stella981
• 阅读 774

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

1)不同的国家和地区制定了不同的标准,由此产生了 GB2312、GBK、Big5、Shift_JIS 等各自的编码标准。这些使用 1 至 4 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码

(American National Standards Institute美国国家标准学会)

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.字符编码转换(py2和py3的编码区别)

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 之路,致那些年,我们依然没搞明白的编码
http://www.cnblogs.com/alex3714/articles/7550940.html

py编码终极版
http://www.cnblogs.com/yuanchenqi/articles/5956943.html

字符串相关
http://www.diveintopython3.net/strings.html

unicode与gbk的映射表
http://www.unicode.org/charts/

完毕,呵呵呵呵

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这