在计算机内部,全部信息都是由一串位来表示,表明的数据对象取决于它所处的上下文,多是数字、字符串或其余。当为字符串时,相信不少人遇到过乱码问题,产生乱码的根本缘由和字符集及其编码有关。vue
0x61表示字符'a'
。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/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
ISO-8859-x系列编码其实就是ISO 2022标准中各组件的特定组合。编码
单字节对于CJK字符来讲显然不够用,ISO/IEC 2022标准在ISO 646标准(其前身就是ASCII)的基础上,规范了大字符集的表示。7-bit编码除了空格和33个控制字符外,总共能定义94个图形字符,也就是说2个7-bit编码可表示94x94个字符,三字节能表示更多。lua
GB2312
就是我国根据ISO/IEC 2022标准,制定的简体中文编码标准字符集。GB2312中的字符就排列在94x94的方阵中,总共有8836个码位,行称为区,列称为位,利用区号和位号能够肯定一个字符,称为字符的区位码(码点),这里的码点使用的是十进制。url
区 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 给每一个字符提供了一个惟一的数字,称做码点(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-8
和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为低位代理。其余补充平面编码规则为:
计算机中大多以字节为单位,那么一个16位码元的序列,就须要解决字节序的问题。UTF-16容许在实际编码值以前加一个字节序标记 (Byte Order Mark ,BOM)
,值为0xFEFF
表示big-endian
,值为0xFFFE
表示little-endian
。Unicode 默认是 big-endian。
举个例子,求码点U+10393的编码:
FEFFD800DF93
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编码:
Unicode是字符集,而UTF-8是Unicode的一种编码方案。
这个是微软的锅,它给UTF-8加上的,通常仍是不要加BOM了。
通常是使用了错误的字符集。避免乱码的最好方法就是统一编码(最好都是UTF-8),或者是知道字符的原始编码方式。