如果经常写python2,肯定会遇到各种“奇怪”的字符编码问题,每次都通过谷歌解决了,但是为什么会造成这种乱码、decode/encode失败等等,本文就字符和字符编码做一个总结,更加清晰区分诸多的编码。

字符集

一个系统支持的所有抽象字符的集合。字符是文字和符号的总称,包含各个国家文字、标点符号、图像符号、数字等。它为每一个字符分配一个唯一的ID,一般称之为码位、码点。

字符编码

它是一套规则,使用该规则能够将自然语言的字符的一个集合与其他东西的一个集合进行配对,在符号集合和数字系统中建立映射联系。在计算机中,处理信息是利用元件不同状态组合来存储和处理信息的,因此,字符编码就是将符号转化为计算机可以接受的数字系统的数,称为数字代码。它将上面字符集的码位转化为字节序列的规则,此过程称之为编码、解码。

常见字符集

ASCII字符集,GB2312字符集、Unicode字符集等。计算机需要准确处理各种字符集文字,需要进行字符编码,以便能够识别和存储各种文字。

常见字符编码

UTF编码

ASCII码

在计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit),有0和1两种状态,因此,8个二进制位可以组合出256种状态,这被称为字节(byte)。上个世纪60年代,美国制定了一套字符编码,对英文字符与二进制之间做了联系,这被称为ASCII码,一直沿用至今。

ASCII码一共规定了128个字符,比如SPACE是32,A是65,这128个符号只咱用了一个字节的后面七位,最前面的一位统一规定为0。

非ASCII码

英语用128个符号编码足够了,但是用来表示其他语言显然是不够的,于是,欧洲有些国家利用字节中闲置的最高位编入了新的符号,这样一来,欧洲国家使用的编码体系,可以最多表示256个字符。

但是到了亚洲国家,使用的符号更多了,光汉字就10万多个,一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。比如常见的GB2312编码,使用两个字节表示一个汉字,所以理论上最多可以表示256*256=65536个符号。

GBK码

GBK编码是对GB2312的扩展,完全兼容GB2312。采用双字节编码方案,剔出xx7F码位,共23940个码位,共收录汉字和图形符号21886个,GBK编码方案于1995年12月15日发布。它几乎完美支持汉字,因此经常会遇见GBK与Unicode的转换。

Unicode码

如上文所述,世界上有多种编码方法,同一个二进制数字可以被解释称不同的符号。因此,在打开一个文本文件时候,就必须知道它的编码方式,用错误的编码方式打开,就会出现乱码。

假如,有一种编码,将世界上所有的符号都纳入其中,每一种符号都给予独一无二的编码,那么乱码问题就不会存在了。因此,产生了Unicode编码,这是一种所有符号的编码。

Unicode显然是一个巨大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如U+0041表示英语的大写字母A,U+4e25表示汉字严。

在Unicode庞大的字符集的优势下,还存在一个问题,比如一个汉字,“严”的Unicode是十六进制4e25,转成二进制足足有15位,也就是,这个符号需要2个字节,表示其他字符还存在3个字节或者更多。计算机怎么区别三个字节表示的是同一个符号而不是分开表示三个呢?如果Unicode统一规定,每个符号用3个字节表示,但是某些字母显然不需要3个,那么就浪费了空间,文本文件大小超出了很多,这显然是不合理的。直到UTF8字符编码出现了。

UTF8字符编码

随着互联网的发展,强烈要求出现一种统一的编码方式。UTF8就是在互联网中使用最多的对Unicode的实现方式。还有其他实现,比如UTF16(字符用2个字节或者4个字节表示),UTF32(字符用4个字节表示)。UTF8是Unicode的实现方式之一,也是最为常见的实现方式。

UTF8的最大特点是,它是一种变长编码,可以使用1-4个字节表示一个符号,根据不同的符号来变化字节长度。

UTF8编码规则只有两条:

1)对于单字节的符号,字节的第一位设为0,后面的7位为这个符号的Unicode码。因此,对于英文字母,UTF8编码和ASCII编码是相同的。

2)对于非单字节(假设字节长度为N)的符号,第一个字节的前N位都设为1,第N+1设为0,后面字节的前两位一律设为10,剩下的没有提及的二进制,全部为这个符号的Unicode码。

下面总结下编码规则:

Unicode符号范围     |        UTF-8编码方式
(十六进制) | (二进制)
----------------------+---------------------------------------------
- 007F | 0xxxxxxx
- 07FF | 110xxxxx 10xxxxxx
- FFFF | 1110xxxx 10xxxxxx 10xxxxxx
- FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

举个例子,以汉字“严”为例,它的Unicode是4e25(100111000100101),对应上表,处于第三行,因此严的UTF8编码需要3个字节。然后,从严的最后一个二进制位开始,从后向前填入X,多出的位补0,就可以计算出 11100100 10111000 10100101,转成十六进制就是E4B8A5。

Unicode与UTF8之间转换

严的Unicode编码是4e25,UTF8是E4B8A5,两者是不一样的,可以通过程序实现转码。

在Windows下有记事本小程序notepad.exe,打开文件后可以通过另存为,选择编码格式,重新保存新的文本文件。支持ANSI,Unicode,Unicde big endlian和UTF8。

1)ANSI是记事本默认编码方式,对于简体中文是GB2312。正是因为这个,Python读取文本文件时候一定要小心它的编码类型,因为不能直观到文本文件的格式。

2)Unicode编码这里使用UCS-2编码方式,采用两个字节存入字符的Unicode编码。

Python编码为什么如此蛋疼

总结了几种编码和编码规则,但是在Python2中编码问题就像幽灵一样困扰着开发者,其根本解决办法是理解清楚python2在内存中的字符存在的编码格式,在程序代码中始终采用Unicode编码处理,只有在输出时候才做encode处理。核心思想是:保证Python运行过程中字符编码格式是unicode编码,在任何地方。关于Python乱码问题,会在专门文章做分析,这里提供一个链接供参考。

Python编码为什么那么蛋疼?

编码探测

使用 chardet 可以很方便的实现字符串/文件的编码检测。尤其是中文网页,有的页面使用GBK/GB2312,有的使用UTF8,使用chardet基本可以探测出编码格式。

延伸阅读

谈谈Unicode编码

ASCII,Unicode,GBK和UTF-8字符编码的区别和联系的更多相关文章

  1. ASCII、Unicode、GBK和UTF-8字符编码的区别联系(转载)

    ASCII.Unicode.GBK和UTF-8字符编码的区别联系 转载自:http://dengo.org/archives/901 很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同 ...

  2. day008 字符编码之 字符编码 、Python2和Python3字符编码的区别

    计算机基础(掌握) 启动应用程序的流程 双击qq 操作系统接受指令然后把该操作转化为0和1发送给CPU CPU接受指令然后把指令发送给内存 内存接受指令把指令发送给硬盘获取数据 qq在内存中运行 文本 ...

  3. Python2和3字符编码的区别

    Python2和3字符编码的区别 一.字符编码应用之Python 1.1 执行Python程序的三个阶段 Python test.py(我再强调一遍,执行test.py的第一步,一定是先将文件内容从硬 ...

  4. 第六篇.文件处理之python2和3字符编码的区别

    目录 python2和3字符编码的区别 一.字符编码应用之python python2和3字符编码的区别 一.字符编码应用之python 1执行python的三个阶段 python test.py 执 ...

  5. 50-Python2和3字符编码的区别

    目录 Python2和3字符编码的区别 python2 python3 Python2和3字符编码的区别 区别点 python2 python3 print 是一个语法结构 是一个函数,print(' ...

  6. ASCII、Unicode、GBK和UTF-8字符编码的区别联系

    转自http://dengo.org/archives/901 很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物.他们看到8个开关状态是好的,于是他们把这称 ...

  7. ASCII、Unicode、GBK和UTF-8字符编码的区别联系[转]

    http://dengo.org/archives/901 这是我看过的最好的一篇讲述编码的文章 很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物.他们看到 ...

  8. 浅析ASCII、Unicode和UTF-8三种常见字符编码

    什么是字符编码? 计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255( ...

  9. 常见三种字符编码的区别:ASCII、Unicode、UTF-8

    什么是字符编码? 计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255( ...

随机推荐

  1. Spring Data Solr相关配置

    1.增加Maven POM文件的存储库:pom配置如下: <repositories> <repository> <id>spring-milestone</ ...

  2. [原创] JAVA 递归线程池测试 ExecutorService / ForkJoinPool

    测试工具使用递归的方式获取子进程的Msg消息,目前有2种常用的ExecutorService / ForkJoinPool 为了测试哪种效果较好,我们来写个测试Demo,循环5555555次+1(加锁 ...

  3. python学习笔记八(集合)

    集合 set是一个无序的不重复元素序列. 用大括号或set()函数创建集合.注意:创建一个空集合用set(),不用{},{}用来创建空字典 basket = {'apple','orange','ap ...

  4. bzoj5109: [CodePlus 2017]大吉大利,晚上吃鸡!

    Description 最近<绝地求生:大逃杀>风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏.在游戏中,皮皮 和毛毛最喜欢做的事情就是堵桥,每每有一个好时机都能收到不少的快 ...

  5. 2.NB-IoT及通信协议

    NB-IoT 1.什么是NB-IoT? NB-IoT全称窄带物联网(Narrow Band IOT),构建于蜂窝网络,只消耗大约180KHz的带宽,可直接部署于GSM网络.UMTS网络或LTE网络,以 ...

  6. MFC如何添加bmp文件和ICO文件

    1.添加BMP格式文件如下图所示: 2.添加ICO格式文件如下图所示:

  7. OkGo3.0 --真实项目使用和二次封装(转)

    转载:https://blog.csdn.net/jiushiwo12340/article/details/79011480  11.OkGo3.0真实项目使用和二次封装: ====  11.OkG ...

  8. mybatis逆向工程没有报错,但是也没有pojo和Mapper文件问题

    如果你使用的逆向工程是自己手写上去的配置文件,那么错误的范围就太大了.如果是你导入以前使用过的逆向工程,那么没有生成文件很可能是使用的操作系统不同. 原因:逆向工程中的路径问题,windows和mac ...

  9. 基础总结(01)--css清除浮动几种方法

    1.父元素添加overflow:auto/hidden; 2.父元素内加空div,添加样式clear:both; 3.父元素添加伪类; .parent:after{ content:''; displ ...

  10. python selenium 基本常用操作

    最近学习UI自动化,把一些常用的方法总结一下,方便自己以后查阅需要.因本人水平有限,有不对之处多多包涵!欢迎指正! 一.xpath模糊匹配定位元素 武林至尊,宝刀屠龙刀(xpath),倚天不出(css ...