如果经常写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. Elasticsearch-6.7.0系列(五)5044端口 logstash安装

    centos7环境 下载logstash wget https://artifacts.elastic.co/downloads/logstash/logstash-6.7.0.tar.gz      ...

  2. 7.6.1 continue 语句

    7.6.1 continue 语句 3种循环都可以使用CONTINUE语句.执行到该语句时,会跳过本次迭代的剩余部分,并开始下一轮迭代.如果continue语句在嵌套循环内,则只会影响包含该语句的内层 ...

  3. LeetCode【101. 对称二叉树】

    对称二叉树,就是左节点的左节点等于右节点的右节点,左节点的右节点等于右节点的左节点. 很自然就想到迭代与递归,可以创建一个新的函数,就是另一个函数不断的判断,返回在主函数. class Solutio ...

  4. Apartment 2019:(1)创建墙体

    墙体建模 The Walls 软件:SketchUp Pro 2017 墙体模型 建模过程: 一.导入图像并调整大小 导入公寓平面参考图/户型图(来自网络),导入为图像.连续三击鼠标左键,选中所有的几 ...

  5. HTML+CSS 对于英文单词强制换行但不截断单词的解决办法

    如何处理长的单词和链接(强制换行,连接符,省略号等) 我们在前端开发中经常会遇到一些很长的文本串从它的容器中溢出,例如: 通过这样一段css可以有效解决这种问题: .dont-break-out { ...

  6. js对象原型prototype

    javascript中的每个对象都有prototype属性,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用. 每一个构造函数都有一个属性叫做原型 1.1. 原型法设 ...

  7. 获取geometry边界范围的示例代码

    根据sqlserver geometry数据定义获取空间类型边界范围 --获取指定街道边界的xy最大最小值 ) '--街道编码 create table #temp_point(id int iden ...

  8. Java解析XML之Dom4j

    Java解析XML文件的方法有多种,个人感觉最常用的是使用Dom4j来解析XML文件.下面就简单介绍下Dom4j的基础使用. Dom4j需要jar包的支持,大家可以从网络上下载,如dom4j-1.6. ...

  9. jvisualvm远程连接

    1. 今天用jvisualvm远程连接linux上的jdk,jxm方式没有连接成功,后来发现是tomcat安装目录bin下的catalina.sh文件下的JAVA_OPTS中内容格式不对,要有空格,修 ...

  10. 部署Redis4.x单机版及配置RDB和AOF持久化

    一.环境及软件 OS soft version  CentOS 7.5   redis-4.0.12(目前是4.x最新) 二.下载及编译Redis [root@localhost ~]# wget h ...