字符编码(英语:Character encoding)、字集码是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。计算机中的字符编码算是一个历史遗留性问题,因为各个国家种族对应着不同的问题,以及各个组织机构推出不同的标准,因此现在计算机中的字符编码格式繁多。

打开某网页,或者用记事本打开某文本文件时,我们可能会看到一堆的乱码如”бЇЯАзЪСЯ”、”�????????”,出现这种问题,往往是我们选用的字符编码不对。

简介

计算机中储存的信息都是用二进制数表示的;而我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果。也就是说,我们在计算机中存储数据时,字母 ‘a’ 需要用什么二进制来表示,这便称为”编码”;反之,将存储在计算机中的二进制数解析显示出来,称为”解码”,如同密码学中的加密和解密。而如果在解码过程中我们使用了错误的规则,则会导致解码错误 ‘a’ 变成了 ‘0’。

字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。

字符编码(Character Encoding):是一套法则,使用该法则能够对自然语言的字符的一个集合(如字母表或音节表),与其他东西的一个集合(如号码或电脉冲)进行配对。即在符号集合与数字系统之间建立对应关系,它是信息处理的一项基本技术。通常人们用符号集合(一般情况下就是文字)来表达信息。而以计算机为基础的信息处理系统则是利用元件(硬件)不同状态的组合来存储和处理信息的。元件不同状态的组合能代表数字系统的数字,因此字符编码就是将符号转换为计算机可以接受的数字系统的数,称为数字代码。

常用编码

常见字符编码为:ASCII,GB2312,UTF-8,Unicode,Big5等,下面我们对其中一些详细阐述。

ASCII

ASCII(1963年)和EBCDIC(1964年)这样的字符集逐渐成为标准。最早的时候计算机ASCII码只能表示256个符号(含控制符号),这个字符集表示英文字母足够。使用7位(bits)表示一个字符,共128字符;但是7位编码的字符集只能支持128个字符,为了表示更多的欧洲常用字符对ASCII进行了扩展,我们通常成为扩展 ASCII 码,其使用 8位(bits)表示一个字符,共256字符。

一般标准 ASCII 码是每个学计算机的人必须知道和了解的,对常用的一些字符所表示的二进制能够非常熟悉,例如:(0-9)->(0x30-0x39) (A-Z)->(0x41-0x5A) (a-z)->(0x61-7A) NULL->(0x00) 等。

虽然 ASCII 的使用范围很广,但表示汉字、日语、韩语就不太够用了,汉字常用字有3000多个。这些字符集的局限很快就变得明显,于是人们开发了许多方法来扩展它们,于是就有了其他一些新兴字符集的出现。

GB2312

计算机发明之处及后面很长一段时间,只用应用于美国及西方一些发达国家,ASCII能够很好满足用户的需求。但对于亚洲众多国家来说并不适用,当计算机传入我国后,为了显示中文,必须设计一套编码规则用于将汉字转换为计算机可以接受的数字系统的数。

于是国内指定了国标 GB2312(中国国家标准简体中文字符集),全称《信息交换用汉字编码字符集·基本集》,又称GB0,由中国国家标准总局发布,1981年5月1日实施。GB2312编码通行于中国大陆;新加坡等地也采用此编码。

中国大陆几乎所有的中文系统和国际化的软件都支持GB2312。GB2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。对于人名、古汉语等方面出现的罕用字,GB2312不能处理,这导致了后来GBK及GB 18030汉字字符集的出现。

GB2312 定义的规则如下:一个小于 127 的字符的意义与原来相同(即:兼容 ASCII 码标准),但两个大于 127 的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从 0xA1 用到 0xF7,后面一个字节(低字节)从 0xA1 到 0xFE,这样我们就可以组合出大约 7000 多个简体汉字了,GB2312 是对 ASCII 的中文扩展。

在这些编码里,还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在 127 号以下的那些就叫”半角”字符了,也就不难看出为何我们平时选用全角输入数字字母时,会发现样式变宽了,占用了多个位置,这也是因为采用全角后,每个字符占用了两个字节,一般我应该要避免使用这种情况输入。

GB2312 后来发现还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准,GBK 包括了 GB2312 的所有内容,同时又增加了近 20000 个新的汉字(包括繁体字)和符号。后来少数民族也要用电脑了,于是我们再扩展,又加了几千个新的少数民族的字,GBK 扩成了 GB18030。

Big5

Big5,又称为大五码或五大码,是使用繁体中文(正体中文)社区中最常用的电脑汉字字符集标准,共收录13,060个汉字。Big5虽普及于台湾、香港与澳门等繁体中文通行区,但长期以来并非当地的国家标准,而只是业界标准。Big5码是一套双字节字符集,使用了双八码存储方法,以两个字节来安放一个字。第一个字节称为”高位字节”,第二个字节称为”低位字节”。”高位字节”使用了0x81-0xFE,”低位字节”使用了0x40-0x7E,及0xA1-0xFE。这边不再对该编码做过多的介绍。

Unicode

Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。

Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字”严”。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表。

从unicode开始,无论是半角的英文字母,还是全角的汉字,它们都是统一的一个字符(并不是一个字节,而是两个字节)。在unicode中,一个字符就是两个字节,一个汉字不再类似于 GB2312 中当作两个字符来处理了。

unicode同样有着自身的问题,一个是,如何才能区别 unicode 和 ascii 。计算机如何知道三个字节表示一个符号,而不是分别表示三个符号呢?二是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是 0,这对于过去计算机来说存储空间极为珍贵,而这样做无疑造成了极大的浪费,文本文件的大小会因此大出两三倍,这是难以接受的。

unicode在很长一段时间内无法推广,直到互联网的出现,为解决unicode如何在网络上传输的问题,于是面向传输的众多 UTF(UCS Transfer Format)标准出现了。UTF-8 就是每次8个位传输数据,而UTF-16就是每次16个位传输。UTF-8 就是在互联网上使用最广的一种 unicode 的实现方式,这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。

可以这样理解:Unicode是字符集,UTF-32/ UTF-16/ UTF-8是三种字符编码方案。

UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8就是在互联网上使用最广的一种Unicode的实现方式。其他实现方式还包括UTF-16(字符用两个字节或四个字节表示)和UTF-32(字符用四个字节表示),不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8是Unicode的实现方式之一。

UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8 的编码规则很简单:

  • 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 unicode 码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
  • 对于 n 字节的符号(n>1),第一个字节的前 n 位都设为 1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 unicode 码。

下面是对比 Unicode 和 UTF-8 的对比:

Unicode 符号范围 UTF-8 编码方式
(十六进制) (二进制)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

下面,还是以汉字”严”为例,演示如何实现UTF-8编码。已知”严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此”严”的UTF-8编码需要三个字节,即格式是”1110xxxx 10xxxxxx 10xxxxxx”。然后,从”严”的最后一个二进制位开始,依次从后向前填入格式中的 x,多出的位补 0。这样就得到了,”严”的 UTF-8 编码是 “11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

BOM头

UTF-8 本来是兼容性最好的编码,但 Windows 偏要加 BOM 于是经常出问题。

在 utf-8 编码文件中 BOM 在文件头部,占用三个字节,用来标识该文件属于 utf-8 编码,现在已经有很多软件识别 BOM 头,但还是有些不能识别 BOM 头,比如 PHP 就不能识别 BOM 头,这也就是用记事本编辑 utf-8 编码的 PHP 文件后,就会报错的原因。

在windows环境下,用记事本打开任何一个文本文件,另存为utf-8格式后,这样文件就自动被加上了BOM头信息。含BOM头的文件,在文件开头处多出三个字节 0xefbbbf。

windows 下一般不建议使用记事本打开文本文件,就如上面所提到的原因,记事本会加入 BOM 头,与此同时,记事本在处理其他平台传过来的文本时还有其他问题,因此计算机工作者,编辑文本时,推荐使用 notepad++ 或者 editplus。这些软件都可以兼容多个平台的文本文件,同时编辑能力强,打开速度快,能够直接各种格式的编码。


To be continued…

https://www.zhihu.com/question/20650946
https://zh.wikipedia.org/wiki/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81
http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html
http://baike.baidu.com/link?url=HknfN5Mei0ekD1hoPPs-U1osSOA1tDDFYkfPfNa05SNX36LbaAh4ctHt_2XhefTVW03ZCRLaBw1dYpY6iG3-ea
https://www.zhihu.com/question/23374078
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
http://www.cnblogs.com/lfire/archive/2012/11/20/2778939.html