页首

字符编码

character coding

跟随历史的足迹看字符编码

古代的通信方式

很久很久以前,人们之间的长途通讯主要是用信鸽、骑马送报、烽烟等方式进行

直到1837年,世界第一条电报诞生,当时美国科学家莫尔斯尝试用一些“点”和“划”来表示不同的字母、数字和标点符号,这套表示字符的方式也被称为“摩尔斯电码”

世界第一台计算机

再后来到了1946年,世界第一台计算机诞生。发明计算机的同学们用8个晶体管的“通”或“断”组合出一些状态来表示世间万物,不过当时的计算机有一间半教室那么大,六头大象重,从现在看来这简直就是个怪物,但在当时却是震惊世界与改变世界的一项重要发明

ASCII (American Standard Code for Information Interchange)

8个晶体管的“通”或“断”即可以代表一个字节,刚开始,计算机只在美国使用,所有的信息在计算机最底层都是以二进制(“0”或“1”两种不同的状态)的方式存储,而8位的字节一共可以组合出256(2的8次方)种状态,即256个字符,这对于当时的美国已经是足够的了,他们尝试把一些终端的动作、字母、数字和符号用8位(bit)来组合

128个码位,用7位二进制数表示,由于计算机1个字节是8位二进制数,所以最高位为0,即00000000-011111110x00-0x7F

  • 比特(bit):也可称为“位”,是计算机信息中的最小单位,是 binary digit(二进制数位) 的 缩写,指二进制中的一位
  • 字节(Byte):计算机中信息计量的一种单位,一个位就代表“0”或“1”,每8个位(bit)组成一个字节(Byte)
  • 字符(Character):文字与符号的总称,可以是各个国家的文字、标点符号、图形符号、数字等
  • 字符集(Character Set):是多个字符的集合
  • 编码(Encoding): 信息从一种形式或格式转换为另一种形式的过程
  • 解码(decoding): 编码的逆过程
  • 字符编码(Character Encoding): 按照何种规则存储字符

现在我们来看我们文章开头提到的第一条电报的诞生,莫尔斯编码中包含了大小写英文字母和数字等符号。
这里的每一个符号其实就是⌈字符⌋,
而这所有的字符的集合就叫做⌈字符集⌋,
“点”或“划”与字符之间的对应关系即可以称为⌈字符编码⌋。

而电报的原理是:

“点”对应于短的电脉冲信号,“划”对应于长的电脉冲信号,这些信号传到对方,接收机把短的电脉冲信号翻译成“点”,把长的电脉冲信号转换成“划”,译码员根据这些点划组合就可以译成英文字母,从而完成了通信任务。
这里把字符表示为“点”或“划”并对应为电脉冲信号的过程既是⌈编码⌋,

而译码员把接收机接收到的脉冲信号转化成点划后译成字符的过程即为⌈解码⌋。

而对于计算机诞生之后,只不过是将摩斯电码中的“点”和“划”换成了以8位字节二进制流的方式表示,如数字1的二进制流是0011 0001,对应的十进制流是49,十六进制流是31。

奇偶校验

简单来说, 奇偶校验是一种检测数据传输时正确性的方法,它分为 奇校验 和 偶校验两种, 分别检测二进制数据中 “1” 的个数是奇数或偶数。 并将校验结果位追加到数据之后。

  • 奇校验:
    如果数据中的 “1” 的个数是奇数,那么校验位为 0 否则为 1。
    例如: 1001000 => 奇校验 1001000+1 , 1001001 => 奇校验 1001001+0

  • 偶校验:
    如果数据中的 “1” 的个数是偶数,那么校验位为 0 否则为 1。
    例如: 1001000 => 偶校验 1001000+0 , 1001101 => 偶校验 1001101+1
    奇偶校验只能检查错误,但并不能纠正错误。

单字节编码

EASCII (Extended ASCII)

虽然刚开始计算机只在美国使用,128个字符的确是足够了,但随着科技惊人的发展,欧洲国家也开始使用上计算机了。不过128个字符明显不够呀,比如法语中,字母上方有注音符号,于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。

比如,法语的é的二进制流为1000 0010,这样一来,这些欧洲国家的编码体系,可以表示最多256个字符了。 但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,1000 0010在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (?),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0--127表示的符号是一样的,不一样的只是128--255的这一段。 EASCII(Extended ASCII,延伸美国标准信息交换码)由此应运而生,EASCII码比ASCII码扩充出来的符号包括表格符号、计算符号、希腊字母和特殊的拉丁符号:

256个码位,用8位二进制数表示,即00000000-111111110x00-0xFF

ISO-8859 (国际化标准组织-8859)

ISO-8859全称ISO/IEC 8859,是国际标准化组织(ISO)及国际电工委员会(IEC)联合制定的一系列8位字符集的标准,现时定义了15个字符集。
ASCII收录了空格及94个“可印刷字符”,足以给英语使用。但是,其他使用拉丁字母的语言(主要是欧洲国家的语言),都有一定数量的附加符号字母,故可以使用ASCII及控制字符以外的区域来储存及表示。
除了使用拉丁字母的语言外,使用西里尔字母的东欧语言、希腊语、泰语、现代阿拉伯语、希伯来语等,都可以使用这个形式来储存及表示。
按国家/地区分别编码。 ISO陆续语系)的扩充ASCII制定了十多个适用于不同国家和地区(均为拉丁字符集(高位为1的8位代码),称为ISO8859
又称为 扩充ASCII字符集

  • ISO/IEC 8859-1 (Latin-1) - 西欧语言
  • ISO/IEC 8859-2 (Latin-2) - 中欧语言
  • ISO/IEC 8859-3 (Latin-3) - 南欧语言。世界语也可用此字符集显示。
  • ISO/IEC 8859-4 (Latin-4) - 北欧语言
  • ISO/IEC 8859-5 (Cyrillic) - 斯拉夫语言
  • ISO/IEC 8859-6 (Arabic) - 阿拉伯语
  • ISO/IEC 8859-7 (Greek) - 希腊语
  • ISO/IEC 8859-8 (Hebrew) - 希伯来语(视觉顺序)
  • ISO 8859-8-I - 希伯来语(逻辑顺序)
  • ISO/IEC 8859-9(Latin-5 或 Turkish)- 它把Latin-1的冰岛语字母换走,加入土耳其语字母。
  • ISO/IEC 8859-10(Latin-6 或 Nordic)- 北日耳曼语支,用来代替Latin-4。
  • ISO/IEC 8859-11 (Thai) - 泰语,从泰国的 TIS620 标准字集演化而来。
  • ISO/IEC 8859-13(Latin-7 或 Baltic Rim)- 波罗的语族
  • ISO/IEC 8859-14(Latin-8 或 Celtic)- 凯尔特语族
  • ISO/IEC 8859-15 (Latin-9) - 西欧语言,加入Latin-1欠缺的芬兰语字母和大写法语重音字母,以及欧元(€)符号。
  • ISO/IEC 8859-16 (Latin-10) - 东南欧语言。主要供罗马尼亚语使用,并加入欧元符号。

由于英语没有任何重音字母(不计外来词),故可使用以上十五个字集中的任何一个来表示。
至于德语方面,因它除了 A-Z, a-z 外,只用 Ä, Ö, ü, ä, ö, ß, ü 七个字母,而所有拉丁字集(1-4, 9-10, 13-16)均有此七个字母,故德语可使用以上十个字集中的任何一个来表示。
此系列中没有-12号的原因是,此计划原本要设计成一个包含塞尔特语族字符集的“Latin-7”,但后来塞尔特语族变成了ISO 8859-14 / Latin-8。亦有一说谓-12号本来是预留给印度天城体梵文的,但后来却搁置了。

这套编码规则由ISO组织制定。是在 ASCII 码基础上又制定了一些标准用来扩展ASCII编码,即 00000000(0) ~ 01111111(127) 与ASCII的编码一样,对 10000000(128) ~ 11111111(255)这一段进行了编码,如将字符§编码成 10100111(167)。ISO-8859-1编码也是单字节编码,最多能够表示256个字符。Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。但是,即使能够表示256个字符,对中文而言,还是太少了,一个字节肯定不够,必须用多个字节表示。但是,由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用 ISO8859-1编码来表示。而且在很多协议上,默认使用该编码。比如,虽然"中文"两个字不存在ISO8859-1编码,以GB2312编码为例,应该是D6D0 CEC4两个字符,使用ISO8859-1编码的时候则将它拆开为4个字节来表示:D6D0 CEC4(事实上,在进行存储的时候,也是以字节为单位进行处理)。而如果是UTF编码,则是6个字节e4 b8 ad e6 96 87。很明显,这种表示方法还需要以另一种编码为基础才能正确显示。而常见的中文编码方式有GB2312、BIG5、GBK。

多字节编码

GB2312

EASCII码对于部分欧洲国家基本够用了,但过后的不久,计算机便来到了中国,要知道汉字是世界上包含符号最多并且也是最难学的文字。 据不完全统计,汉字共包含了古文、现代文字等近10万个文字,就是我们现在日常用的汉字也有几千个,那么对于只包含256个字符的EASCII码也难以满足天朝的需求了。 于是⌈中国国家标准总局⌋(现已更名为⌈国家标准化管理委员会⌋)在1981年,正式制订了中华人民共和国国家标准简体中文字符集,全称《信息交换用汉字编码字符集·基本集》,项目代号为GB 2312 或 GB 2312-80(GB为国标汉语拼音的首字母),此套字符集于当年的5月1日起正式实施。

GB2312 是最早(1980年)发布的中国国家标准字符集 ,是一个典型的双字节字符集(DBCS)。 他规定了两个连续大于 127 的字节代表一个汉字, 否则就当做 ASCII 来处理, 这样的两字节中高位字节范围 0xA1-0xF7, 低位字节范围 0xA1-0xFE。 二者相乘多出来 8000 多个坑位, 已经足够容纳常用汉字了, 除此之外还增加了数学符号、罗马希腊字母、日文假名等。 这种规则完全兼容 ASCII , 但为了更好的兼容 CP437 也做了很多空间牺牲, 比如 GB2312 的低位也被要求大于 127, 所以 GB2312 的编码空间并不大。

包含字符:

1981年5月1日发布的简体中文汉字编码国家标准。GB2312对汉字采用双字节编码,收录7445个图形字符,其中包括6763个汉字,682个其他字符(拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母)

存储方式:

基于EUC存储方式,每个汉字及符号以两个字节来表示,第一个字节为“高位字节”,第二个字节为“低位字节”

GB2312其对所收录字符进行了"分区"处理,共94个区,区从1(十进制)开始,一直到94(十进制),每区含有94个位,位从1(十进制)开始,一直到94(十进制),共8836(94 * 94)个码位,这种表示方式也称为区位码,GB2312是双字节编码,其中高字节表示区,低字节表示位。各区具体说明如下:

  • 01-09区收录除汉字外的682个字符,有164个空位(9 * 94 - 682)。
  • 10-15区为空白区,没有使用。
  • 16-55区收录3755个一级汉字(简体),按拼音排序。
  • 56-87区收录3008个二级汉字(简体),按部首/笔画排序。
  • 88-94区为空白区,没有使用。

那么根据区位码如何算出GBK2312编码呢?区位码的表示范围为0101 - 9494(包含了空的区位码)。查看中GB2312编码区位码。之后只需要按照如下规则进行转化即可。

  1. 将区(十进制)转化为十六进制。
  2. 将转化的十六进制加上A0,得到GB2312编码的高字节。
  3. 将位(十进制)转化为十六进制。
  4. 将转化的十六进制加上A0,得到GB2312编码的低字节。
  5. 组合区和位,区在高字节,位在低字节。
  6. 得到GB2312编码。

例如:'李'字的区位码为3278(表示在32区,78位)。

  1. 将32(区)转化为十六进制为20。
  2. 加上A0为C0。3. 将78(位)转化为十六进制为4E。
  3. 加上A0为EE。
  4. 组合区和位,为C0EE。
  5. 得到GB2312编码,即'李'字的GB2312编码为C0EE。

GB2312用两个字节编码,采用分区编码,总共编码的中文个数为6763(3755 + 3008)。这些汉字只是最常用的汉字,已经覆盖中国大陆99.75%的使用频率。但是,还有一些汉字在GB2312中没有被编码,如'镕'字,在GB2312中就没有被编码,这样就导致了问题,随之就出现了主流的GBK编码。在讲解GBK编码之前,我们另外讲解一下BIG5编码

早期的计算机运算能力非常弱, 而 GB2312 的编码规则无形中又给解码增加了额外负担, 所以为了提高汉字的输入性能, 一种叫 “汉卡” 的硬件出现了, 他直接负责 GB2312 的编码解码。 为 CPU 分担任务。
但作为一款硬件, 它的流行又使得 GB13000 推行不下去。

BIG5

要知道港澳台同胞使用的是繁体字,而中国大陆制定的GB2312编码并不包含繁体字,于是信息工业策进会在1984年与台湾13家厂商签定“16位个人电脑套装软件合作开发(BIG-5)计划”,并开始编写并推出BIG5标准。 之后推出的倚天中文系统则基于BIG5码,并在台湾地区取得了巨大的成功。在BIG5诞生后,大部分的电脑软件都使用了Big5码,BIG5对于以台湾为核心的亚洲繁体汉字圈产生了久远的影响,以至于后来的window 繁体中文版系统在台湾地区也基于BIG5码进行开发。

包含字符:

共收录13,060个汉字及441个符号

编码方式:

用两个字节来为每个字符编码,第一个字节称为“高位字节”,第二个字节称为“低位字节”

BIG5采用双字节编码,使用两个字节来表示一个字符。高位字节使用了0x81-0xFE,低位字节使用了0x40-0x7E,及0xA1-0xFE。该编码是繁体中文字符集编码标准,共收录13060个中文字,其中有二字为重复编码,即“兀、兀”(A461及C94A)和“嗀、嗀”(DCD1及DDFC)。具体的分区如下:

  • 8140-A0FE 保留给使用者自定义字符(造字区)
  • A140-A3BF 标点符号、希腊字母及特殊符号。其中在A259-A261,收录了度量衡单位用字:兙兛兞兝兡兣嗧瓩糎。
  • A3C0-A3FE 保留。此区没有开放作造字区用。
  • A440-C67E 常用汉字,先按笔划再按部首排序。
  • C6A1-F9DC 其它汉字。
  • F9DD-F9FE 制表符。

Unicode

在计算机进入中国大陆的相同时期,计算机也迅速发展进入了世界各个国家。 特别是对于亚洲国家而言,每个国家都有自己的文字,于是每个国家或地区都像中国大陆这样去制定了自己的编码标准,以便能在计算机上正确显示自己国家的符号。 但带来的结果就是国家之间谁也不懂别人的编码,谁也不支持别人的编码,连大陆和台湾这样只相隔了150海里,都使用了不同的编码体系。 于是,世界相关组织意识到了这个问题,并开始尝试制定统一的编码标准,以便能够收纳世界所有国家的文字符号。 在前期有两个尝试这一工作的组织:

国际标准化组织(ISO)

国际标准化组织(ISO)及国际电工委员会(IEC)于1984年联合成立了ISO/IEC小组,主要用于开发统一编码项目

统一码联盟

而Xerox、Apple等软件制造商则于1988年组成了统一码联盟,用于开发统一码项目。

两个组织都在编写统一字符集,但后来他们发现各自在做相同的工作,同时世界上也不需要两个不兼容的字符集,于是两个组织就此合并了双方的工作成果,并为创立一个单一编码表而协同工作。

1991年,年,两个组织共同的工作成果Unicode 1.0正式发布,不过Unicode 1.0并不包含CJK字符(即中日韩)。

  • Unicode 1.0:1991年10月
  • Unicode 1.0.1:1992年6月
  • Unicode 1.1:1993年6月
  • Unicode 2.0:1997年7月
  • Unicode 2.1:1998年5月
  • Unicode 2.1.2:1998年5月
  • Unicode 3.0:1999年9月
  • Unicode 3.1:2001年3月
  • Unicode 3.2:2002年3月
  • Unicode 4.0:2003年4月
  • Unicode 4.0.1:2004年3月
  • Unicode 4.1:2005年3月
  • Unicode 5.0:2006年7月
  • Unicode 5.1:2008年4月
  • Unicode 5.2:2009年10月
  • Unicode 6.0:2010年10月
  • Unicode 4.1:2005年3月
  • Unicode 6.1:2012年1月31日
  • Unicode 6.2:2012年9月

ISO/IEC 8859

ISO/IEC小组在1984年成立后的第三年(即1987年)开始启动ISO 8859标准的编写,ISO 8859是一系列8位字符集的标准,主要为世界各地的不同语言(除CJK)而单独编写的字符集,一共定义了15个字符集

其中ISO/IEC 8859-1至ISO/IEC 8859-4四个项目早在1982年就已经编写出来,只不过是由ANSI与ECMA合作完成,并于1985年正式公布,ISO/IEC小组成立后,这一成果被其收录,并改名为ISO/IEC 8859 前四个项目。 大家其实发现以上15个字符集中并没有代号为“ISO/IEC 8859 -12”的字符集,据说-12号本来是预留给印度天城体梵文的,但后来却搁置了(阿三有了自己的编码-ISCII)。由于英语没有任何重音字母,故可使用以上十五个字符集中的任何一个来表示。

ISO/IEC 10646 / UCS

1993年,ISO/IEC 10646标准第一次发表,ISO/IEC 10646是ISO 646的扩展,定义了1个31位的字符集。ISO 10646标准中定义的字符集为UCS,UCS是Universal Character Set的缩写,中文译作通用字符集。

版本
  • ISO/IEC 10646-1:第一次发表于1993年,现在的公开版本是2000年发表的ISO/IEC 10646-1:2000。
  • ISO/IEC 10646-2:在2001年发表。
包含字符:

最初的ISO 10646-1:1993的编码标准,即Unicode 1.1,收录中国大陆、台湾、日本及韩国通用字符集的汉字共计20,902个,当然每个版本的Unicode标准的字符集所包含的字符数不尽相同,UCS包含了已知语言的所有字符,除了拉丁语、希腊语、斯拉夫语、希伯来语、阿拉伯语、亚美尼亚语、格鲁吉亚语,还包括中文、日文、韩文这样的方块文字,此外还包括了大量的图形、印刷、数学、科学符号。 UCS给每个字符分配一个唯一的代码,并且赋予了一个正式的名字,通常在表示一个Unicode值的十六进制数的前面加上“U+”,例如“U+0041”代表字符“A”。

编码方案:

UCS仅仅是一个超大的字符集,关于UCS制定的编码方案有两种:UCS-2和UCS-4,Unicode默认以UCS-2编码。 顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。那么UCS-2其实可以容纳的字符数为65536(2的16次方),而UCS-4可以容纳的字符数为2147483648(2的31次方)。其实对于UCS-2已经是完全够用了,基本可以包含世界所有国家的常用文字,如果需要考虑一些偏僻字,那么UCS-4则绝对可以满足了,21亿个字符哪怕是整个宇宙也够用了吧!

UTF

Unicode 诞生,随之而来的计算机网络也发展了起来,Unicode 如何在网络上传输也是一个必须考虑的问题,于是在1992年,面向网络传输的UTF标准出现了。 UTF是Unicode Transformation Format的缩写,中文译作Unicode转换格式。其实我们从现在可以把Unicode看作是一个标准或组织,而UCS就是一个字符集,那么UCS在网络中的传输标准就是UTF了。 前面提到了UCS的编码实现方式为UCS-2和UCS-4,即要么是每个字符为2个字节,要么是4个字节。如果一个仅包含基本7位ASCII字符的Unicode文件,每个字符都使用2字节的原Unicode编码传输,其第一字节的8位始终为0,这就造成了比较大的浪费。但是,聪明的人们发明了UTF-8,UTF-8采用可变字节编码,这样可以大大节省带宽,并增加网络传输效率。

UTF-8

虽然 unicode 帮我们解决了字符集统一的问题,但这并不是没代价的。 在 unicode 下所有的字符都是用 2(UCS2) 或 4(UCS4) 个字节来编码,甚至是 ASCII 字符。 这样便造成了大量浪费,尤其是在进行网络传输的时候。 (当你走进联通营业厅后会发现, 流量啊 流量。 你可是真金白银啊。)

为了解决这一问题, 科学家们定义了一种基于 unicode 的便于传输的编码格式 UTF(UCS Transfer Format), UTF 也有 UTF-8 UTF-16 UTF-32 这几个兄弟 横杠后的数字代表尝试将单个 unicode 压缩成几 bit。

比如 UTF-8 它就将尝试用 8 bit 来表示一个 unicode 字。

十六进制                    二进制
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
  1. 如果某字节第一位是 0 ,那么判定为 ASCII 字节,除了 0 外余下的 7 位是 ASCII 码。所以 UTF-8 是兼容 ASCII 码的。
  2. 如果第一个字节是 1 , 那么连续的几个 “1” 代表了从这个字符开始,后面连续的几个字符其实是一个字位。 且后面的位置都要是用 10 开头的。

使用1~4个字节为每个UCS中的字符编码:
128个ASCII字符只需一个字节编码(Unicode范围由U+0000至U+007F)
拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母需要二个字节编码(Unicode范围由U+0080至U+07FF)
大部分国家的常用字(包括中文)使用三个字节编码
其他极少使用的生僻字符使用四字节编码

UTF-16/UCS-2

UCS-2的父集,使用2个或4个字节来为每个UCS中的字符编码:
128个ASCII字符需两个字节编码
其他字符使用四个字节编码

UTF-32/UCS-4

等同于UCS-4,对于所有字符都使用四个字节来编码

GB13000

前面提到了Unicode的迅速发展,至1993年时,包含CJK的Unicode 1.1已经发布了,天朝的ZF也意识到了需要一个更大的字符集来走向世界,于是在同一年,中国大陆制定了几乎等同于Unicode1.1的GB13000.1-93国家编码标准(简称GB13000)中华人民共和国信息产业部把Unicode重新修订发布了下,改为了国家标准GB13000。此标准等同于 ISO/IEC 10646.1:1993和Unicode 1.1。

GBK

鉴于我国汉卡的流行情况, 我国有关部门又制定了 GBK 标准,它兼容 GB2312, 同时又新增了 2w 多个坑位。
它是怎么做到的呢?
GBK 放开了一些范围, 相比 GB2312 , GBK 的高位字节扩展到了 0×81-0xFE, 低位字节扩展到了 0x40-0xFE (不包含0x7F) 编码方式和 GB2312 相同。
由此可见 GBK 是 GB2312 的一个超集, 且和子集兼容良好。

1995年,在GB13000诞生后不久,中国教育科研网(NCFC)与美国NCFnet直接联网,这一天是中国被国际承认为开始有网际网路的时间。此后网络正式开始在中国大陆接通,个人计算机开始在中国流行,虽然当时只是高富帅才消费得起的产品。中国是一个十几亿人口的大国,微软意识到了中国是一个巨大的市场,当时的微软也将自己的操作系统市场布局进中国,进入中国随之而来要解决的就是系统的编码兼容问题。 之前的国家编码标准GB2312,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。但对于人名、古汉语等方面出现的罕用字和繁体字,GB2312不能处理,因此微软利用了GB2312中未使用的编码空间,收录了GB13000中的所有字符制定了汉字内码扩展规范GBK(K为汉语拼音 Kuo Zhan中“扩”字的首字母)。所以这一关系其实是大陆把Unicode1.1借鉴过来改名为了GB13000,而微软则利用GB2312中未使用的编码空间收录GB13000制定了GBK。所以GBK是向下完全兼容GB2312的。

包含字符:

共收录21886个字符, 其中汉字21003个, 字符883个

编码方式:

GBK只不过是把GB2312中未使用的空间,编码了其他字符,所以GBK同样是用两个字节为每个字符进行编码。

GB18030

微软到了99年前后,说GBK已经落伍了,现在流行UTF-8标准,准备全盘转换成UTF-8。GB18030的诞生还有一个原因是GBK只包含了大部分的汉字和繁体字等,我们的少数民族兄弟根本木有考虑!中国有56个民族,其中有12个民族有自己的文字,那怎么办呢?在2000年,电子工业标准化研究所起草了GB18030标准,项目代号“GB 18030-2000”,全称《信息技术-信息交换用汉字编码字符集-基本集的扩充》。此标准推出后,在中国大陆之后的所售产品必须强制支持GB18030标准.

GB18030 是目前我国最新的内码字集, 它和其他 GB 开头的小伙伴最大的区别就是,它是变长的编码集。
所谓变长是指一个 GB18030 字有可能由 1 个、2 个或 4 个字节组成。 与 UTF 系列类似。

它与 GBK , GB2312 , ASCII 都是兼容的。

  • 1 字节的值范围: 0 到 0x7F,与 ASCII 兼容。
  • 2 字节的值范围: 高位 0x81 到 0xFE。 低位 0x40 到 0xFE 与 GBK 标准兼容。
  • 4 字节的值范围: 一字节 0x81 到 0xFE,二字节 0x30 到 0x39,三字节 0x81 到 0xFE,四字节从 0x30 到 0x39

GB18030 可容纳的编码范围巨大, 基本上亚洲所有的少数民族的文字都包含在内了。
可以看出在这 GB 几兄弟中 GB2312 => GBK => GB18030 被依次兼容。

包含字符:

GB18030收录了GBK中的所有字符,并将Unicode中其他中文字符(少数民族文字、偏僻字)也一并收录进来重新编码。其中GB 18030-2000共收录27533个汉字,而GB 18030-2005共包含70244个汉字。

编码方式:

采用多字节编码,每个字符由1或2或4个字节进行编码

BOM (byte-order mark)

为Unicode标准为了用来区分一个文件是UTF-8还是UTF-16或UTF-32编码方式的记号,又称字节序。

UTF-8以单字节为编码单元,并没有字节序的问题,而UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?这是UTF-16文件开头的BOM就有作用了。

采用Unicode编码方式的文件如果开头出现了“FEFF”,“FEFF”在UCS中是不存在的字符,也叫做“ZERO WIDTH NO-BREAK SPACE”,那么就表明这个文件的字节流是Big-Endian(高字节在前)的;如果收到“FFFE”,就表明字节流是Little-Endian(低字节在前)。

在UTF-8文件中放置BOM主要是微软的习惯,BOM其实是为UTF-16和UTF-32准备的,微软在UTF-8使用BOM是因为这样可以把UTF-8和ASCII等编码明确区分开,但这样的文件在Window以外的其他操作系统里会带来问题。

字符编码区别

UCS-2 与 UTF-16区别

从上面的分析知道,UCS-2采用的两个字节进行编码。在0000到FFFF的码位范围内,它和UTF-16基本一致,为什么说基本一致,因为在UTF-16中从U+D800到U+DFFF的码位不对应于任何字符,而在使用UCS-2的时代,U+D800到U+DFFF内的值被占用。

UCS-2只能表示BMP内的码点(只采用2个字节),而UTF-16可以表示辅助平面内的码点(采用4个字节)。

我们可以抽象的认为UTF-16可看成是UCS-2的父集。在没有辅助平面字符(surrogate code points)前,UTF-16与UCS-2所指的意思基本一致。但当引入辅助平面字符后,想要表示辅助平面字符时,就只能用UTF-16编码了。

UCS-4与 UTF-16的区别

在BMP上,UTF-16采用2个字节表示,而在辅助平面上,UTF-16采用的是4个字节表示。对于UCS-4,不管在哪个平面都采用的是四个字节表示。

为什么UTF-8编码不需要BOM机制

因为在UTF-8编码中,其自身已经带了控制信息,如1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx,其中1110就起到了控制作用,所以不需要额外的BOM机制。

锟斤拷锟斤拷烫烫烫烫。

手持两把锟斤拷,口中疾呼烫烫烫。
脚踏千朵屯屯屯,笑看万物锘锘锘。
锟(0xEFBF)
斤(0xBDEF)
拷(0xBFBD)

“锟斤拷” 主要出现在 GBK 和 Unicode 混用的网页中。在比较老的 web 服务器上是重灾区。
想打造出 “锟斤拷” 需要三位仙人配合: html文件,web server 和 浏览器。
制造流程是, 你的 html文件是 GBK 的而 web server 把它强行用 unicode 解码,解码后发现味儿不对, 将转码失败的字全部用 「U+FFFD」 代替,然后将「U+FFFD」 转成 utf-8 后又发给了浏览器。
「U+FFFD」转为 utf-8 后为 \xEF\xBF\xBD , 如果是两个连续的 「U+FFFD」那结果就是 \xEF\xBF\xBD\xEF\xBF\xBD
最后你的浏览器用 GBK 解码 \xEF\xBF\xBD\xEF\xBF\xBD 你便得到了神器”锟斤拷”

See

All rights reserved

posted @ 2018-03-04 14:41  zhangrxiang  阅读(714)  评论(0编辑  收藏  举报

页脚