前言
这里不会过多的介绍一些背景和历史,只是把这些知识点归纳一下,有需要的话还是需要自行查找相关的文章进行延伸阅读,在这里记录也是因为之前虽然已经有了一定的了解,但是一来时间久了,二来之前的理解还是有部分模糊的地方,所以这里打算整理总结下
概念
Encoding:就是一种数字到字符的映射
Code Page:有很多不同的字符编码,那么内码表这个概念就是用于表述在当前使用场景(打开某个文件等)下的字符编码
Big endian/Little endian:单字节的处理不存在大/小端的概念,只有针对多个字节作为一个整体来处理时才存在大/小端的区别,如short、int这样的情况;小端就是低地址存储数字的低位,而大端则相反,低地址存储的是数字的高位;这里要特别注意的一点就是:字符编码的编码单元是字节时,是不会有字节序这样的问题的,因为如果有多个字节表示一个字符,其编码方案已经制定了字节的顺序,所以诸如GBK、UTF-8这样的编码是没有字节序的问题的,只有UTF-16等以word为编码单元的字符编码,才需要考虑字节序的问题
ASCII
ASCII码定义了128个字符,那么使用1个字节就可以表示了。
规定字节最高位始终为0,使用剩下的7位表达全部的128个字符(0x00-0x7F)
GB2312/GBK
通过对字节最高位设为1,来对ASCII码进行扩展;
从GB2312到GBK是一个不断扩充的字符集,GBK向下兼容GB2312;GBK和GB2312也同时兼容ASCII,这样就可以同时处理中英文字符;
GB2312和GBK都属于双字节字符集(DBCS),这样可以在处理DBCS字节流的时候,如果遇到一个字节最高位为1的字节时,可以直接把下一个字节和这个字节结合起来对应出一个中文字符;
Unicode
Unicode是一种容纳全世界所有符号的字符编码方案,它只规定了如何编码,并没有规定如何传输、保存这个编码;可以把Unicode视为一种标准或规范,真正要使用还是需要一个具体的实现,这就是UTF-8、UTF-16、UCS-2、UCS-4这些具体实现方案了(类似进行了二次映射,字符->Unicode->UTF-8/UTF-16);
Code Point:码点是Unicode的概念,实际就是字符对应的数字,使用类似U+XXXX这样的形式来表达;Unicode的码空间从U+0000到U+10FFFF,可以表示一百多万个字符;
Universal Character Set简称UCS,虽然属于另一个组织发布的(IEEE),但是两个组织发布的这两种标准Unicode和UCS互相兼容;虽然有那么一些定义上的差别(UCS使用31位,而Unicode只使用21位),但实质上两者现在完全相同,更进一步的细节阐释,可以参看这篇文章Unicode 字符集、编码 相关的基本介绍
BMP:Basic Multilingual Plane,码位从U+0000到U+FFFF,基本包括了最常见的字符
另外需要注意的是Unicode是以抽象的方式定义了字符,如伸出舌头的脸这样,并没有规定要如何呈现
Unicode的实现方案
UCS-2/UCS-4:这是一种定长编码,表示用2个字节或4个字节来实现UCS标准,并且这种编码的方式和码点是一一对应的,不像UTF系列还需要做些转换;UCS-2由于2个字节的限制,实质上只能表达BMP内的字符
UTF-8:变长编码,以字节为编码单元,一个字符占用1~6个字节(实际上最多只用4个字节就可以表示所有Unicode码点,4个字节以上的是针对UCS的更高的码点空间)
UTF-16:也是变长编码,但是以word为编码单元;对于U+0000到U+FFFF内的码点,和UCS-2一致,使用2个字节表示;对于U+10000以上的码点,使用代理对的方式用4个字节表示;word为编码单元,就带来了大/小端的问题,所以有UTF-16LE和UTF-16BE
UTF-32:定长编码,和UCS-4是一样的
BOM
字节序(Byte Order Mark),�由于UTF-16存在大/小端的问题,所以规定了使用0xFEFF来作为BOM标记,来表明文件或传输流使用的字节序;虽然UTF-8没有字节序的问题,但是也可以借用这个BOM来表明自己是用UTF-8编码的,0xFEFF的UTF-8编码是EF BB BF(这个并不强制,所以UTF-8的文件有可能有BOM头,也有可能没有)
系统使用的编码
Windows的内核使用的是UTF-16编码,但是VC使用的是UCS-2(所以wchar_t就可以存储一个字符)
MacOS也是使用的UTF-16编码,Clang默认源文件为UTF-8编码,而OC里的NSString代表的是用UTF-16编码的文本,很多方法涉及的长度、索引和范围都是基于UTF-16的码元;注意是码元,而不是字符,尽管很多方法都是使用类似character这个词,例如length返回的是码元的个数,如果NSString包含的字符都是BMP内的,那这个length就是字符个数,而一旦有BMP外字符或组合字符时,这个length就不是准确的字符个数了;类似的还有characterAtIndex:这个方法返回的是一个码元unichar类型;更详细的信息和处理参见这篇文章NSString 与 Unicode