如果经常写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. Linux 学习目录

    1 VIM 快捷键

  2. 三、thymeleaf模板引擎构建前台html, 后台使用 ModelAndView 和 Model 模型

    项目源码:https://github.com/y369q369/springBoot.git      ->     thymeleaf 私聊QQ: 1486866853 1.pom.xml中 ...

  3. Service Worker 离线无法缓存Post请求的问题解决

    许多非REST API甚至可以用于读取数据的POST请求:典型的例子是graphql.soap和其他rpcpapi.但是,Post请求不能在一个现成的渐进式Web应用程序中缓存和脱机使用.浏览器的缓存 ...

  4. 如何以system身份运行指定的程序?

    Local System(本地系统)是Windows操作系统内置的特殊账户.它拥有比Administartor更高的权限.smss.exe(会话管理器).csrss.exe(客户端/服务器运行时子系统 ...

  5. spring框架篇(一)-------spring简介与配置文件使用控制反转事例

    spring简介 Spring 是一个开源框架,中文意思就是春天,也许是作者想让自己的这个框架给Java开发人员带来春天吧.其官方网站是 https://spring.io/ ,可以在官方网站下载到完 ...

  6. Jmeter连接数据库方式

    关系型数据库: 1.mysql: 方式:Database URL:jdbc:mysql://localhost:port/DBname?user=**&password=**&allo ...

  7. MySQL计算年龄

    SELECT TIMESTAMPDIFF(YEAR, birthday, now()) FROM person2;

  8. NodeJS-静态服务器

    静态服务器 代码 const http = require('http') const chalk = require('chalk') const conf = require('./config/ ...

  9. Revit 命令添加下拉框

    在学习revit制作下拉框时,需要分为三个步骤: 1.创建一个面板(panel). RibbonPanel panel10 = application.CreateRibbonPanel(Global ...

  10. Python的内置函数

    python的内置函数一共有68个,下面将简单介绍各个函数的功能. abs() dict() help() min() setattr() all() dir() hex() next() slice ...