理解计算机

字符编码笔记:ASCII、ANSI、Unicode

2018-12-19  本文已影响11人  零岁的我

一、基础知识

计算机中储存的信息都是用二进制数表示的;而我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果。通俗的说,按照何种规则将字符存储在计算机中,如'a'用什么表示,称为"编码";反之,将存储在计算机中的二进制数解析显示出来,称为"解码",如同密码学中的加密和解密。在解码过程中,如果使用了错误的解码规则,则导致'a'解析成'b'或者乱码。


二、字符编码分类

常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。

2.1ASCII字符集&编码

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语,而其扩展版本EASCII则可以勉强显示其他西欧语言。它是现今最通用的单字节编码系统(但是有被Unicode追上的迹象),并等同于国际标准ISO/IEC 646。

ASCII只能支持现代美国英语,对更多其他语言语言的显示则无能为力。

2.2 ANSI多字节编码(本地化)

对于中文 DOS 系统和早期的中文 Windows 系统,大陆制定了国标码 GB2312,台港澳地区则使用了大五码 Big5。微软针对这些本地化字符编码采用的就是用 ANSI(American National Standards Institute,美国国家标准学会)多字节编码方式,系统里的英文和符号就使用单字节的 ASCII(0x00~0x7f),而对于汉字之类的本地化字符编码,就采用 0x80~0xFF 范围内的多个字节来表示,这样既能兼容 ASCII ,又能正常使用本地化语言文字。大陆的国标码发展了好几代,归结如下:

ANSI 多字节编码解决了各种语言文字的本地化使用问题,也有它自己的缺陷:各地制定的编码标准只对自己的语言文字有效,而不同语言文字的编码都是冲突的,因为大家都用 0x80~0xFF 范围字节表示自己的语言文字,而不考虑别的语言文字如何编码,冲突在所难免。比如简体中文(GBK)的文本放到繁体中文(Big5)的操作系统里,就被默认解析成繁体字编 码,两种编码是冲突的,就会显示混乱的繁体字,反过来也一样。微软公司使用了代码页(Codepage)转换表的技术来过渡性的部分解决这一问题,即通过指定的转换表将非 Unicode 的字符编码转换为同一字符对应的系统内部使用的 Unicode 编码。可以在“语言与区域设置”中选择一个代码页作为非 Unicode 编码所采用的默认编码方式,如936为简体中文GBK,950为正体中文Big5(皆指PC上使用的)。在这种情况下,一些非英语的欧洲语言编写的软件和文档很可能出现乱码。而将代码页设置为相应语言中文处理又会出现问题,这一情况无法避免。从根本上说,完全采用统一编码才是解决之道,但目前尚无法做到这一点。

2.3 Unicode问题(国际化)

Unicode编码也叫万国码、国际码等,Unicode字符集可以简写为UCS(Unicode Character Set)。早期的Unicode标准有UCS-2、UCS-4的说法。UCS-2用两个字节编码,UCS-4用4个字节编码。这个仅仅是标准,而不是实现,在编码实现的过程中,有些考虑兼容旧的单字节 ASCII 编码,有些不考虑兼容性;有些考虑双字节中哪个字节放在前面,哪个字节放在后面的问题,即 BOM(Byte Order Mark,字节顺序标记)的作用。因此诞生了多种国际码的实现方式,统称为 Unicode 转换格式(Unicode Transformation Format,UTF):


三、Little endian和Big endian

UCS-2 格式可以存储 Unicode 码(码点不超过0xFFFF)。以汉字严为例,Unicode 码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,4E在前,25在后,这就是 Big endian 方式;25在前,4E在后,这是 Little endian 方式。

这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争起因是人们争论,吃鸡蛋时究竟是从大头(Big-endian)敲开还是从小头(Little-endian)敲开。为了这件事情,前后爆发了六次战争,一个皇帝送了命,另一个皇帝丢了王位。

第一个字节在前,就是"大头方式"(Big endian),第二个字节在前就是"小头方式"(Little endian)。

那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?

Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(zero width no-break space),用FEFF表示。这正好是两个字节,而且FF比FE大1。

如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。


四、BOM

  1. BOM的来历
    为了识别 Unicode 文件,Microsoft 建议所有的 Unicode 文件应该以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字符开头。这作为一个“特征符”或“字节顺序标记(byte-order mark,BOM)”来识别文件中使用的编码和字节顺序。
  2. 不同系统对BOM的支持
    因为一些系统或程序不支持BOM,因此带有BOM的Unicode文件有时会带来一些问题。

①JDK1.5以及之前的Reader都不能处理带有BOM的UTF-8编码的文件,解析这种格式的xml文件时,会抛出异常:Content is not allowed in prolog。

②Linux/UNIX 并没有使用 BOM,因为它会破坏现有的 ASCII 文件的语法约定。

③不同的编辑工具对BOM的处理也各不相同。使用Windows自带的记事本将文件保存为UTF-8编码的时候,记事本会自动在文件开头插入BOM(虽然BOM对UTF-8来说并不是必须的)。而其它很多编辑器用不用BOM是可以选择的。UTF-8、UTF-16都是如此。

  1. 决定文本的字符集与编码
    对于Unicode文本最标准的途径是检测文本最开头的几个字节。如:

开头字节 Charset/encoding
EF BB BF    UTF-8
FE FF     UTF-16/UCS-2, little endian(UTF-16LE)
FF FE     UTF-16/UCS-2, big endian(UTF-16BE)
FF FE 00 00  UTF-32/UCS-4, little endian.
00 00 FE FF  UTF-32/UCS-4, big-endia

参考文献

  1. 《字符,字节和编码》http://www.regexlab.com/zh/encoding.htm
  2. 《字符编码详解——彻底理解掌握编码知识,“乱码”不复存在》http://blog.51cto.com/polaris/377468
  3. 《字符编码笔记:ASCII,Unicode 和 UTF-8》http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
上一篇 下一篇

猜你喜欢

热点阅读