1. ASCII码
ASCII (American Standard Code for Information Interchange, 美国标准信息交换代码),是基于拉丁字母的一套编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统。
单个字节可以表示256个不同的字符,不过 ASCII 只使用了其中低于\x80
(即最高位字节为0)的一半来表示所有的英文字符以及一些控制字符,因此 ASCII 码的实际取值范围为0x00
到0x7f
之间,一共128个字符。
2. 多字节字符集MBCS
ASCII字符集中只含有英文字符,不能满足其他语言的需求。于是很多语言就制定了一套自己的编码,由于 ASCII 是单字节的,能表示的字符数量太少,因此这些编码很多都使用多个字节来表示单个字符。例如 GBK 等。 这些编码的规则都比较相似: 如果第一个字节是\x80
以下,则仍然表示 ASCII 字符,而如果是\x80
以上,则跟下一个字节一起(共两个字节)表示一个字符。
IBM发明了一个叫Code Page
的概念,将这些编码都收入囊中并分配页码,GBK 是第936页,也就是CP936
。所以,也可以使用CP936
表示 GBK 。
这些各种语言自己制定的编码统称 MBCS (Multi-Byte Character Set)。目前都是用了双字节,所以有时候也称为 DBCS (Double-Byte Character Set)。必须明确的是,MBCS 并不是指某一种特定的编码,Windows里根据你设定的区域不同,MBCS 代表不同的编码,而Linux里无法使用 MBCS 作为编码。在Windows中你看不到 MBCS 这几个字符,因为微软使用了 ANSI 这个称呼,记事本的另存为对话框里编码 ANSI 就是 MBCS 。在简体中文 Windows 默认的区域设定中,ANSI 代表 GBK 编码。
3. Unicode
由于各种不同的 MBCS 编码互相不兼容,使用、转换起来很不方便,于是便有了 Unicode 。
Unicode (万国码、国际码、统一码、单一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。
Unicode 发展由非营利机构统一码联盟负责,该机构致力于让Unicode方案替换既有的字符编码方案。因为既有的方案往往空间非常有限,亦不适用于多语环境。
Unicode 备受认可,并广泛地应用于电脑软件的国际化与本地化过程。有很多新科技,如可扩展置标语言、Java编程语言以及现代的操作系统,都采用 Unicode 编码。
最初的Unicode标准UCS-2
使用两个字节表示一个字符,一共能表示 256×
个字符,不久后又有人觉得还是太少了,于是出现了用4个字节表示一个字符的UCS-4
标准。
UCS (Unicode Character Set)仅仅是字符对应码位的一张表而已。具体如何传输和储存字符则是由 UTF (UCS Transformation Format)来指定。
一开始直接使用 UCS 的码位来保存字符,这就是UTF-16,比如汉
这个字的码位是6C49
,则直接使用\x6C\x49
保存(UTF-16-BE,BE
指Big Endian),或是倒过来使用\x49\x6C
保存(UTF-16-LE,LE
指Little Endian)。
但是这种保存方式在保存英文字符时,会浪费很多存储空间( ASCII 保存一个字符只需要一个字节),于是变有了 UTF-8。
UTF-8 是一种变长并且兼容 ASCII 的字符编码,在 UTF-8 中 ASCII 字符仍然使用相同的一个字节表示,这使得原来处理 ASCII 字符的软件无须或只须做少部分修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或发送文字的应用中,优先采用的编码。
UTF-8 使用一至六个字节为每个字符编码(尽管如此,2003年11月 UTF-8 被RFC 3629
重新规范,只能使用原来 Unicode 定义的区域,U+0000
到U+10FFFF
,也就是说最多四个字节):
- 128个 US-ASCII 字符只需一个字节编码(Unicode 范围由
U+0000
至U+007F
). - 带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要两个字节编码( Unicode 范围由
U+0080
至U+07FF
)。 - 其他基本多文种平面( BMP) 中的字符(这包含了大部分常用字,如大部分的汉字)使用三个字节编码(Unicode 范围由
U+0800
至U+FFFF
)。 - 其他极少使用的 Unicode 辅助平面的字符使用四至六字节编码(Unicode 范围由
U+10000
至U+1FFFFF
使用四字节,Unicode 范围由U+200000
至U+3FFFFFF
使用五字节,Unicode 范围由U+4000000
至U+7FFFFFFF
使用六字节)。
对上述提及的第四种字符而言,UTF-8 使用四至六个字节来编码似乎太耗费资源了。但 UTF-8 对所有常用的字符都可以用三个字节表示,而且它的另一种选择,UTF-16 编码,对前述的第四种字符同样需要四个字节来编码,所以要决定 UTF-8 或 UTF-16 哪种编码比较有效率,还要视所使用的字符的分布范围而定。
另外值得一提的是 BOM (Byte Order Mark)。我们在储存文件时,文件使用的编码并没有保存,打开时则需要我们记住原先保存时使用的编码并使用这个编码打开,这样一来就产生了许多麻烦。UTF 则引入了 BOM 来表示自身编码,如果一开始读入的几个字节是其中之一,则代表接下来要读取的文字使用的编码是相应的编码:
BOM | BYTES |
---|---|
BOM_UTF8 |
\xef\xbb\xbf |
BOM_UTF16_LE |
\xff\xfe |
BOM_UTF16_BE |
\xfe\xff |
并不是所有的编辑器都会写入 BOM ,但即使没有 BOM,Unicode 还是可以读取的,只是像 MBCS 的编码一样,需要另行指定具体的编码,否则解码可能会失败。
绝大多数编辑器在没有BOM时都是以 UTF-8 作为默认编码读取。即使是保存时默认使用 ANSI (MBCS)的记事本,在读取文件时也是先使用 UTF-8 测试编码,如果可以成功解码,则使用 UTF-8 解码。这个别扭的做法造成了一个BUG:如果你新建文本文件并输入姹塧
然后使用 ANSI 保存,再打开就会变成 汉a
。
参考资料: