字符集和编码

在计算机内部,全部信息都是由一串位来表示,表明的数据对象取决于它所处的上下文,多是数字、字符串或其余。当为字符串时,相信不少人遇到过乱码问题,产生乱码的根本缘由和字符集及其编码有关。vue

  • 字符集(Character set):各类文字和符号的总称,如ASCII字符集、Unicode字符集。
  • 字符编码(Character encoding):指定位模式与字符符号的映射关系,如0x61表示字符'a'

ASCII

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是英文字符的一种编码方案。ASCII 字符集有两类字符:控制字符和可打印字符。java

标准ASCII码使用1字节(8-bit)中的 7 位表示,总共 2^7=128 种字符(0x00~0x7F),最高位为0。其中前32个代码和最后一个为控制字符;0x20~0x7E 为可打印字符,表明英文字母、数字、标点符号以及一些杂项符号,共95个。c++

ASCII码已经可以知足现代英语的信息交换,但它们不能处理大部分欧洲国家的语言,由于他们还使用其余拉丁字母的字符(如带音标的),此外不一样国家用到的字符也不一样,为了解决这个问题,ISO建立了ISO 2022标准,规范了7位和8位编码的多个字符集中的字符,以及大字符集的表示,后来被应用于建立Latin-1,ISO 8859-1标准。markdown

ISO 8859

ISO 8859全称为ISO/IEC 8859,是一系列8-bit编码字符集的标准,它经过扩展ASCII码,利用 8-bit 中的第8位添加了另96个可打印字符的位置,其编码区间是 0xA0~0xFF。ISO 8859定义了15个字符集,其中常见的是ISO 8859-1,西欧语言字符集app

这里不得不提一下ISO-8859-1,它是IANA(互联网号码分配机构)根据ISO/IEC 8859-1标准制定的8-bit编码字符集,别名latin1,编码范围是0x00~0xFF,各区间字符状况以下:ui

  • 0x00~0x7F,依据ASCII字符集
  • 0x80~0x9F,ISO/IEC 2022中的C1控制字符
  • 0xA0~0xFF,依据ISO 8859-1,西欧语言字符集

ISO-8859-x系列编码其实就是ISO 2022标准中各组件的特定组合。编码

GB2312/GBK

单字节对于CJK字符来讲显然不够用,ISO/IEC 2022标准在ISO 646标准(其前身就是ASCII)的基础上,规范了大字符集的表示。7-bit编码除了空格和33个控制字符外,总共能定义94个图形字符,也就是说2个7-bit编码可表示94x94个字符,三字节能表示更多。lua

GB2312就是我国根据ISO/IEC 2022标准,制定的简体中文编码标准字符集。GB2312中的字符就排列在94x94的方阵中,总共有8836个码位,行称为区,列称为位,利用区号和位号能够肯定一个字符,称为字符的区位码(码点),这里的码点使用的是十进制。url

  • 01-09,包括标点符号和其余特殊字符
  • 16-55,一级汉字,按拼音排列。(3755个字符)
  • 56-87,二级汉字,按部首和笔画排列。(3008个字符)

区 10-15 和 88-94 未分配。spa

GB2312字符集一般使用1字节或2字节的8位EUC-CN(一个多字节字符编码)编码,以便兼容ASCII码,其余汉字符号使用2-Byte表示。编码规则:第一个字节称高位字节,范围是0xA1~0xF7(01-87区号加上0xA0);第二个字节称低位字节,范围是0xA1~0xFE(01-94位号加上0xA0)。好比“创”的码点是2020(0x1414),那么编码就是0xB4B4。之因此要加上0xA0,我以为是为了区分ASCII编码。

GBK是GB2312字符集的扩展,扩展了GB2312未分配的码点,放弃了ISO 2022规定的控制字符块,扩展了字节的范围,第一个字节从A1~FE扩展到了81~FE(94+32=126),第二个字节40~FE(191),总共24,066个位置。

Unicode

Unicode 给每一个字符提供了一个惟一的数字,称做码点(code points),一般使用U+十六进制数来引用码点,好比U+0041表示字符 ‘A’。Unicode 定义了1,114,112个码点的代码空间,范围从 U+0000 到 U+10FFFF,代码空间又分为17个平面(0-16),每一个平面有65,536个码点。其中0号平面叫作基本多语言平面(Basic Multilingual Plane, BMP),BMP范围是U+0000~U+FFFF,使用4个hex数表示码点。BMP以外的代码点,使用5或6个hex数表示。

Unicode能够经过不一样的编码方案来实现,最经常使用的是UTF-8UTF-16

UTF-16

UTF-16 以16-bit为代码单元(code units,2-Byte)对Unicode码点编码,BMP中的码点编码与UTF-16码元相等,好比码点U+2020,UTF-16编码为0x2020。其余补充平面使用代理对(surrogate pairs),即两个码元表示一个码点。

在BMP中,Unicode标准保留U+D800~U+DFFF这部分码点用于高和低位代理的UTF-16编码,其中U+D800~U+DBFF为高位代理,U+DC00~U+DFFF为低位代理。其余补充平面编码规则为:

  • 码点减去0x10000,保留0x000000..0x0FFFFF范围内20位数
  • 用高10位bit加上0xD800给出第一个16位代码单元或高位代码
  • 用低10位bit加上0xDC00给出第二个16位代码单元或低位代码

计算机中大多以字节为单位,那么一个16位码元的序列,就须要解决字节序的问题。UTF-16容许在实际编码值以前加一个字节序标记 (Byte Order Mark ,BOM),值为0xFEFF表示big-endian,值为0xFFFE表示little-endian。Unicode 默认是 big-endian。

举个例子,求码点U+10393的编码:

  • 0x10393-0x10000=0x393,那么高10bit为0x0,低10bit为0x393
  • 则高位代码为0x0+0xD800=0xD800,低位代码为0x393+0xDC00=0xDF93
  • 按照大端序最终UTF-16的编码为FEFFD800DF93

UTF-8

UTF-8 是一种可变长度的编码方案,以8-bit为码元,是互联网普遍使用的一种Unicode实现方式,由于它字节少流量小。UTF-8使用1~4个字节对Unicode代码空间中的有效码点编码。其编码规则是,前128个字符(US-ASCII)使用一个字节编码,与ASCII相对应;接下来1920个字符使用两个字节编码;BMP其他字符须要三个字节,其中包含了大多数中文;其余平面中的字符使用四个字节。

下表是UTF-8编码规则,其中x由码点的位替换:

字节|码位| 码点范围           | 编码方式
----+-------------------------+---------------------------------------
  1 |  7 | U+0000  ~ U+007F   | 0xxxxxxx
  2 | 11 | U+0080  ~ U+07FF   | 110xxxxx  10xxxxxx
  3 | 16 | U+0800  ~ U+FFFF   | 1110xxxx  10xxxxxx  10xxxxxx
  4 | 21 | U+10000 ~ U+10FFFF | 11110xxx  10xxxxxx  10xxxxxx  10xxxxxx

UTF-8使用8-bit代码单元,避免了字节序的问题。求U+10393的UTF-8编码:

  • 0x10393 > 0x10000据上表,使用4字节编码
  • 将0x10393转成二进制0001 0000 0011 1001 0011,从右到右依次替换编码中的x
  • 替换结果为11110000 10010000 10001110 10010011,即 F0908E93

FAQ

1. Unicode和UTF-8是什么关系?

Unicode是字符集,而UTF-8是Unicode的一种编码方案。

2. UTF-8的BOM?

这个是微软的锅,它给UTF-8加上的,通常仍是不要加BOM了。

3. 乱码出现的缘由?

通常是使用了错误的字符集。避免乱码的最好方法就是统一编码(最好都是UTF-8),或者是知道字符的原始编码方式。

相关文章
相关标签/搜索