「MISC」字符编码 - ASCII, EASCII, ANSI, EUC, GBK, Unicode, UTF-8

编程的过程中,难免会碰到一些关于编码的问题,其中对于使用简体中文的中国人来讲最多见的就是 UTF-8GBK
大部分的时候都可以使用语言内置的转换函数或者一些库来进行编码的检测和转码,可是当出现一些乱码的时候,每每有些不知所措,不知道为何会出现这样的码点,也不知如何去解决它。这主要是因为对编码方式的极度不了解。但若是知道不一样的格式是如何编码的,程序是如何解析的,那么乱码的问题便不是问题。编程

下面会对 ASCII, EASCII, ANSI, EUC, GB2312, GBK, UNICODE, UTF-8 和与之相关的一些术语进行解释,相关的编码方式进行阐述,从根本上解决让人头疼的编码问题。windows

ASCII

ASCII - American Standard Code for Information Interchange编辑器

古老(1967)的编码方式,也是最简单的编码方式,使用 7 bits 囊括了26个基本拉丁字母、阿拉伯数字、经常使用英文标点符合和彼时经常使用的控制字符,但如今大部分的ASCII控制字符都已经被废弃使用。
简单的编码会让编码解码变得简单,可是缺点也显而易见——它没法知足其余语言的编码需求。函数

下图是 ISO/IEC 646 定义的标准的 ASCII 7 bits 码表,其容许各国对除了英文字母和数字的其余部分修改,以知足本国需求。
ISO/IEC 646编码

EASCII

EASCII - Extended American Standard Code for Information Interchangespa

EASCII 顾名思义,其在ASCII的基础上拓展了1 bit,总共达到了8 bits,能够多显示128个字符。
EASCII 编码方式比较混乱,在不一样的平台和协议上常常不相同,但咱们主要接触到的有两种:ISO/IEC 8859-1 (Latin-1),Code page 437。操作系统

在这里有必要补充说明一下什么是代码页(Code page)
代码页是windows上命令行中的编码表,不一样的代码页标识着不一样的编码方式,下面是其中一些代码页编号对应的编码方式:.net

  • 437: OEM United States命令行

  • 1252: ANSI Latin 1; Western European (Windows)设计

  • 65001: Unicode (UTF-8)

  • 936: ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312); GBK

  • ...

其中代码页1252与 ISO/IEC 8859-1 (Latin-1)基本一致,如下两图分别为代码页1252和代码页437:

Code page 1252
Code page 437

Windows所有的代码页对应表能够查看 https://msdn.microsoft.com/en...

ANSI

ANSI - American National Standards Institute

这个名称的来历,是一个很是长的故事。咱们如今说的,常常看到的通常都是Window的记事本另存为里面的ANSI编码。

它确实是ANSI这个机构所发布的 8-bit 编码标准(虽然基本上是抄 ISO 8859)。可是微软使用编码标准的时候没有注意到其实ANSI是一套标准,仅仅将它表示Latin-1。
后来逐步的,Windows的国际版本愈来愈多。如今,Windows上面的ANSI编码表明的是操做系统本地的默认代码页,例如在中文版Windows10上就指的是GBK。

许多文章说 GBK、BIG-5 是属于ANSI编码的,其实不对。

EUC

EUC - Extended Unix Code

EUC 是一个符合 ISO 2022 标准的 8-bit 的编码方法。
EUC 定义了4个码集:

  • CS0:ASCII 7 bits编码标准,即 ISO 646;一个字节

  • CS1: MSB(最高有效位)必须为1,0xA0-0xFF;任意字节数

  • CS2: MSB必须为1,第一个字节必须为0x8E,0xA0-0xFF;任意字节数

  • CS3: MSB必须为1,第一个字节必须为0x8F,0xA0-0xFF;任意字节数

CS1,CS2,CS3规定范围在0xA0-0xFF实际上是为了兼容 ISO 2022

每一个码集中都要知足以下条件:

  • 码集中每一个字符都须要使用 相同的字节数

  • 码集中每一个字符在等宽终端中都显示相同的宽度

也就是说,我决定将某些字符用CS1中的码来编码,那么这些落在CS1中的字符必须所有是一个、两个、三个、... 、N个字节,不容许在同一个码集的字符有些是一个字节,有些又是其余数量的字节。

GB2312, GBK

GB - 国标

    • 扩(展)

GB2312又称GB0,是EUC的一种实现,它只使用了CS1,而且规定CS1为两个字节。
上面已经详细的介绍了EUC,那么GB2312的编码方式也很是明朗了。遇到MSB为0的,则读取一个字节;而遇到MSB为1的,则读取两个字节。

抛开具体的字节编码,来看GB2312的设计思路:
它一共分为81个区:

  • 01-09:特殊符号

  • 16-55:一级汉字(经常使用汉字),拼音排序

  • 56-87:二级汉字(很是用汉字),部首/笔画排序

其中10-15,88-94区未有编码,每一个区(从1开始编号)有94(区号 + 0xA0)个字;因此第一个汉字的编码就是(0xA0 + 16) + (0xA0 + 1) = 0xB0A1

关于GBK就不解释太多,只须要知道GBK是GB2312的拓展,向后兼容。

Unicode

Unicode - 一种可以囊括全部字符的编码标准

Unicode分为(0-16)平面+16位编码空间,大部分的经常使用语言的经常使用字符都落在0平面内,也就是0x0000-0xFFFF。
为了向前兼容,Unicode的前256个字符为上面说的ISO标准 8-bit 标准(ISO 8859-1

0 平面也称为基本多文种平面(BMP),各个平面的用途以下:

Unicode平面映射表

Wikipedia - Unicode字符平面映射

ʕ•̀ω•́ʔ✧ 就是这么简单,不比上面各个编码如此复杂

UTF-8

UTF-8 - 8-bit Unicode Transformation Format

既然已经有了编码标准了,接下来就要考虑的就是怎么样把它存到计算机里了。
若是严格的按照Unicode的标准(UTF-32)来存储的话,平面编号占两个字节,编码空间占两个字节,那么不论是只须要7bits的ASCII码抑或是能够用两个字节来表示的经常使用中文,就都得占据四个字节,未免也太浪费(内存、储存空间和带宽资源等)了。

UTF-8是一种变长储存的编码实现方式,对于不一样的字符用1~6个字节来表示。
由于是变长,因此计算机如何区分一个字符是几个字节呢?规则以下:

  • ASCII码范围(0x00-0x7F),使用一个字节表示

  • 超过以上范围的,第一个字节的连续前多少位是1就表示这个字符使用几个字节,例如第一个字节为 0b1110xxxx 就表示包括这个字节在内的,接下来三个字节表示此字符。

UTF-8 储存格式

其实上面这张图我认为将后面6列放到最前面比较合适,可是摆到后面比较好看

能够看到,上面的 x 表明的是有效储存位,其余的都是用来起标识做用的。那么咱们的中文到底占几个字节呢?
查表可知,经常使用汉字的Unicode编码落在基本多文种平面的0x4E00-0x9FFF(中日韩统一表意文字),即三个字节。

认真的人看到这里确定会有一个疑问,为何多字节字符除了第一个字节之外,后面的字节仍是要以0b10开头呢?

让咱们把目光放到上图,能够看到第一个字节没有以0b10开头的。若是后面的字节使用了所有的空间,程序每次定位一个位置都要从头开始查找,由于程序并不知道当前这个字节是不是第一个字节;而若是使用0b10做为开头的话,程序只须要向前查找不是0b10开头的字节,就能够知道它是当前字符的起始字节。

BOM

BOM - Byte-order Mark

因为UTF-16和UTF-32是定长编码,因此在编码单元里面存在大端和小端储存的问题,因此制定了如下规则来标识文件:

UTF BOM 映射表

虽然UTF-8这种变长的编码方式不存在大端小端的问题,可是仍是指定了BOM来表示这个文件是UTF-8。在实际的使用过程中尽可能不要对UTF-8添加BOM,不然不少软件解析都会出现问题。

以后遇到文件前有两个或者三个不知道是什么的字节的时候就不用惊慌了。

编码检测

一直以来都对 notepad++ 等一干智能编辑器如何自动检测文件编码很是好奇,趁此机会查了下资料。

基本上全部的编码检测都不是彻底可靠的,都是根据字节的模式统计分析来肯定最可能的编码,so~
其中能被最可靠的探测到的编码就是UTF-8了,根据上文,UTF-8有大量的0b10xxxxxx以及首字节的定式编码,因此通常来讲不是很容易被检测错误。


✧⁺⸜(●˙▾˙●)⸝⁺✧ 写了一个月的文章完结撒花 ✧⁺⸜(●˙▾˙●)⸝⁺✧

相关文章
相关标签/搜索