【计算机系统导论】2.1 编码

上古时代人们只能面对面交流,传承基本依靠口口相传,直到『仓颉造字』后,文明才有了被系统性编码的机会。广义说来,我们生活中大部分日常所见,都可以认为是编码,那么编码是什么,为什么能起到这么重要的作用,就是我们这一节需要探讨的话题了。


编码,究其根本,是一种用来在机器和人、人和人之间传递信息的标准化方式。在这之上人们发展出了不同的编码系统,从莫尔斯码到布莱叶盲文,以及用于切换状态的优先码/换挡码/逃逸码,我们熟知的 Vim/Emacs 就深受这种设计的影响。

  • 十六进制
  • 文本、数值、图像、声音的表示
  • 字符编码

2.1.1 摩尔斯电码

1838年1月8日,Alfred Vail公司展示了一种使用点和划的电报码,这是摩尔斯电码前身。

最早的摩尔斯电码是一些表示数字的点和划。数字对应单词,需要查找一本代码表才能知道每个词对应的数。用一个电键可以敲击出点、划以及中间的停顿。

虽然摩尔斯发明了电报,但他缺乏相关的专门技术。他与艾尔菲德·维尔签定了一个协议,让他帮自己制造更加实用的设备。艾尔菲德·维尔构思了一个方案,通过点、划和中间的停顿,可以让每个字符和标点符号彼此独立地发送出去。他们达成一致,同意把这种标识不同符号的方案放到摩尔斯的专利中。这就是现在我们所熟知的美式摩尔斯电码,它被用来传送了世界上第一条电报。

这种代码可以用一种音调平稳时断时续的无线电信号来传送,通常被称做“连续波”(Continuous Wave),缩写为CW。它可以是电报电线里的电子脉冲,也可以是一种机械的或视觉的信号(比如闪光)。

一般来说,任何一种能把书面字符用可变长度的信号表示的编码方式都可以称为摩尔斯电码。但现在这一术语只用来特指两种表示英语字母和符号的摩尔斯电码:美式摩尔斯电码被使用在有线电报通信系统;今天还在使用的国际摩尔斯电码则只使用点和划(去掉了停顿)。

在远距离沟通基本依靠电报公司的年代,电报越长,费用也就越高,所以人们设计了五个字符为一组的代码,用一个简写单词来表示一个完整的意思,比如:

  • BYOXO 表示 Are you trying to crawl out of it?
  • LIOUY 表示 Why do you not answer my question?(下次别人不回复消息的时候就发 LIOUY 试试看)
  • AYYLU 表示 Not clearly coded, repeat more clearly

有趣的是,这种利用缩写字符来表示完整意思的方法其实在中国很早之前就出现了,我们所熟知的成语便是利用四字词语来表示一个完整的意思,而在网络时代出现的各种常用词和热梗(比如『活久见』和 『2333』等),都可以认为是传统设计的再次回归。

作为一种信息编码标准,摩尔斯电码拥有其他编码方案无法超越的长久生命。摩尔斯电码在海事通讯中被作为国际标准一直使用到 1999 年。1997 年,当法国海军停止使用摩尔斯电码时,发送的最后一条消息是:『所有人注意,这是我们在永远沉寂之前最后的一声呐喊!』

下面列出一些常见且有趣的缩写,说不定以后大家聊天的时候也可以用上呢:

  • AGN = Again(再一次)
  • C = Yes(是,好)
  • CFM = Confirm(确认)
  • CUL = See you later(再见)
  • CUZ = Because(因为)
  • CY = Copy(抄收)
  • DE = From(来自)
  • GE = Good evening(晚安)
  • GM = Good morning(早安)
  • HI = Laughter(笑)
  • OB = Old boy(老大哥)
  • OC = Old chap(老伙计)
  • OM = Old man(前辈,老手(男性))
  • OT = Old timer(老前辈)
  • OTC = Old timers club(老手俱乐部)
  • OOTC = Old old timers club(资深老手俱乐部)
  • TMW = Tomorrow(明天)
  • TNX = Thanks(谢谢)
  • TU = Thank you(谢谢你)
  • WX = Weather(天气)
  • YL = Young lady(女报务员)
  • 73 = Best regards(致敬)
  • 88 = Love and kisses(吻别)
  • 99 = go way(走开(非友善))

2.1.2 布莱叶盲文

除了最早用于电报的摩尔斯电码,另一种我们日常生活中常见的编码便是盲文,即盲人使用的文字。盲文最早由法国人路易·布莱叶发明,透过盲文板、盲文机、盲文打印机等在纸张上制作出不同组合的凸点而组成。盲文的基本单位是长方形的盲符,有位置固定的六个点,每个点可以凸出(黑色)或不凸出(白色),形成 63 种可能。六个点的分布是左右两行,上中下三层(如下图所示)。左行自上而下称为 1、2、3 点,右行自上而下称为 4、5、6 点。

这里很重要的一点是每个点的状态可以是『凸出』或者『不凸出』,那么这样一来不同的组合就有 64 种(也就是 $2^6=64$),考虑到默认状态是所有都不凸出的,所以这种状态不表示任何含义(不然盲人摸任何空白的地方都要认为这是盲文了),于是最终这种 6 个点的盲文可以表示 63 种含义。后来,随着需要描述的字符的增加(如后文介绍的 ASCII 码共有 256 个字符),盲文也对应需要扩展,故有增至八点的盲文产生(这里 $2^8=256$,可以满足需求)

在我国,由于中文字是方块字,包含多种笔划,故中文盲文都是以盲文拼音,不同方言有个别的盲文系统。显然,中文盲文的缺陷便是容易造成同音异字的混淆。另一个问题,是盲人由于缺乏对汉字的训练,会对汉字一无所知。

中国大陆使用的汉语盲文方案有现行盲文和汉语双拼盲文两种。目前以现行盲文更为通用。两种盲文都是表音文字,通常不区分同音字(必要时除外)。这两个方案的数字表示法相同,都是布莱叶式。
自第四套人民币开始,钞票上亦有用凹版油墨印出钞票金额的盲文。在第五套人民币中,用来表示“0”的三点被连在一起。

台湾盲文又称国语点字。每个音节由三方盲符拼成,分别表示声母、韵母、声调。国语盲文与注音符号一一对应,但是有几点区别:第一声记号不可省略;结合韵不可写成两个韵母;单声母字需加上韵母。

在香港,盲文系统使用广州粤语拼音,粤音共九个声调,由三个方块分别代表由声母、韵母及声调组成一个发音,但第一、第七声不标音,即由二个方块代表包含声母及韵母的第一及第七声单字。另外,如果遇到“零声母”的情况,则要在韵母后加入一空格,以作辨识。

2.1.3 比特与字节

前面提到,盲文是采用点的『凸起』和『不凸起』来区分不同的状态,继而通过不同状态的组合来表示不同的含义的,其实这也就是我们常说的『二进制』,即一个『位』上只有两种状态,称为『二进制位』。

我们将要深入了解的计算机系统,其实就是一个基于二进制位的系统。在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有 0 和 1 两种状态,因此八个二进制位就可以组合出 256 种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示 256 种不同的状态,每一个状态对应一个符号,就是 256 个符号,从 0000000 到 11111111。

一些基本概念如下:

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

莫尔斯编码中包含了大小写英文字母和数字等符号,其中每一个符号其实就是⌈字符⌋,而这所有的字符的集合就叫做⌈字符集⌋,“点”或“划”与字符之间的对应关系即可以称为⌈字符编码⌋。

而电报的原理是:

“点”对应于短的电脉冲信号,“划”对应于长的电脉冲信号,这些信号传到对方,接收机把短的电脉冲信号翻译成“点”,把长的电脉冲信号转换成“划”,译码员根据这些点划组合就可以译成英文字母,从而完成了通信任务。

这里把字符表示为“点”或“划”并对应为电脉冲信号的过程既是⌈编码⌋,而译码员把接收机接收到的脉冲信号转化成点划后译成字符的过程即为⌈解码⌋。

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

还有一个需要注意的是,因为二进制写起来太长,我们经常会采用十六进制来进行记录,下面是一个对照表

十六进制 十进制 二进制 十六进制 十进制 二进制
0 0 0000 8 8 1000
1 1 0001 9 9 1001
2 2 0010 A 10 1010
3 3 0011 B 11 1011
4 4 0100 C 12 1100
5 5 0101 D 13 1101
6 6 0110 E 14 1110
7 7 0111 F 15 1111

2.1.3 ASCII 码

到了1946年,世界第一台计算机诞生。发明计算机的同学们用8个晶体管的“通”或“断”组合出一些状态来表示世间万物。

8个晶体管的“通”或“断”即可以代表一个字节,刚开始,计算机只在美国使用,所有的信息在计算机最底层都是以二进制(“0”或“1”两种不同的状态)的方式存储,而8位的字节一共可以组合出256(2的8次方)种状态,即256个字符,这对于当时的美国已经是足够的了,他们尝试把一些终端的动作、字母、数字和符号用8位(bit)来组合。这一套字符集在1967年被正式公布,称为 ASCII 码(American Standard Code for Information Interchange,美国信息互换标准代码),一直沿用至今。

  • 0000 0000 ~ 0001 1111 共 33 种状态用来表示终端的特殊动作,如打印机中的响铃为 0000 0111 ,当打印机遇到 0000 0111 这样的字节传过来时,打印机就开始响铃;这些0×20以下的字节状态称为”控制码”
  • 0010 0000 ~ 0010 1111 , 0011 1010~0110 0000 和 0111 1101 ~ 0111 1110 共 33 种状态来表示英式标点符号,如 0011 1111 即代表英式问号“?”;
  • 0011 0000 ~ 0011 1001 共 10 种状态来表示“0~9”10个阿拉伯数字;
  • 0100 0001 ~ 0101 1010 和 0110 0001 ~ 0111 1010共 52种状态来表示大小写英文字母;

ASCII 码一共规定了 128 个字符的编码,刚好占用了一个字节中的后7位,共包括 33 个控制字符和 95 个可显示字符。比如空格“SPACE”是32(二进制00100000),大写的字母 A 是65(二进制01000001)。这 128 个符号(包括 32 个不能打印出来的控制符号),只占用了一个字节的后面 7 位,最前面的 1 位统一规定为 0。

英语用 128 个符号编码就够了,但是用来表示其他语言,128 个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的 é 的编码为 130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多 256 个符号。

但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用 256 个符号的编码方式,代表的字母却不一样。比如,130 在法语编码中代表了 é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0—127 表示的符号是一样的,不一样的只是 128—255 的这一段。

中文编码的问题会在下面的章节详细讨论,我们需要注意的是,虽然都是用多个字节表示一个符号,但是 GB 类的汉字编码与后文的 Unicode 和 UTF-8 是毫无关系的。

2.1.4 Unicode 与 UTF-8

正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。

可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是 Universal Multiple-Octet Coded Character Set,简称 UCS,俗称 Unicode,就像它的名字都表示的,这是一种所有符号的编码。

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

Unicode 开始制订时,计算机的存储器容量极大地发展了,空间再也不成为问题了。于是 ISO 就直接规定必须用两个字节,也就是16位来统一表示所有的字符,对于ASCII里的那些“半角”字符,unicode包持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于”半角”英文符号只需要用到低8位,所以其高8位永远是0,因此这种大气的方案在保存英文文本时会多浪费一倍的空间。

这时候,从旧社会里走过来的程序员开始发现一个奇怪的现象:他们的 strlen 函数靠不住了(这个函数主要用于计算字符串的长度,从前是根据字节数量来计算的),一个汉字不再是相当于两个字符了,而是一个!是的,从 unicode 开始,无论是半角的英文字母,还是全角的汉字,它们都是统一的”一个字符“!同时,也都是统一的”两个字节“,请注意”字符”和”字节”两个术语的不同,“字节”是一个8位的物理存贮单元,而“字符”则是一个文化相关的符号。在unicode中,一个字符就是两个字节。一个汉字算两个英文字符的时代已经快过去了。

需要注意的是,Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储,随着我们学习过程的深入,就会意识到一个标准需要好的规范,更需要细节实现,才可能推广开来。

比如,汉字『王』的 unicode 是十六进制数 738B,转换成二进制数足足有15位(111001110001011),也就是说这个符号的表示至少需要 2 个字节。表示其他更大的符号,可能需要 3 个字节或者 4 个字节,甚至更多。

这里就有两个严重的问题,第一个问题是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果 unicode 统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

它们造成的结果是:

  1. 出现了 unicode 的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示 unicode
  2. unicode 在很长一段时间内无法推广,直到互联网的出现

互联网的普及,强烈要求出现一种统一的编码方式。为解决 unicode如何在网络上传输的问题,面向传输的众多 UTF(UCS Transfer Format)标准出现了,顾名思义,UTF-8就是每次8个位传输数据,而 UTF-16 就是每次16个位。UTF-8就是在互联网上使用最广的一种unicode的实现方式,这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。这里有一点需要注意,UTF-8 是 Unicode 的实现方式之一。

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

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

光看理论可能还是不够清晰,这里我们用之前的例子来过一次,先来看看编码规则:

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

已知『王』的 unicode 是 738B(111 001110 001011),属于第三行的范围内(0000 0800-0000 7FFF),因此『王』的 UTF-8 编码需要三个字节,格式为 1110xxxx 10xxxxxx 10xxxxxx。然后,我们从『王』的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了『王』的 UTF-8 编码 11100111 10001110 10001011,转换成十六进制是 E78E8D。

还是以『王』字为例子,738B 需要两个字节存储,一个字节是 73,另一个字节是 8B。存储的时候,73 在前,8B 在后,就是 Big endian方式;8B 在前,73 在后,就是 Little endian 方式。

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

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

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

Unicode 规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做”零宽度非换行空格“(ZERO WIDTH NO-BREAK SPACE),用 FEFF 表示。这正好是两个字节,而且 FF 比 FE 大 1。

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

2.1.5 中文编码那些事儿

前面提到,由美国最先提出并广泛应用的 ASCII 码,因为只有 256 个字符,经过一段时间的发展,等中国人们得到计算机时,已经没有可以利用的字节状态来表示汉字。常用的汉字有 6000 多个,这可怎么办呢?

GB2312

这难不倒智慧的中国人民,⌈中国国家标准总局⌋(现已更名为⌈国家标准化管理委员会⌋)在1981年,正式制订了中华人民共和国国家标准简体中文字符集,全称《信息交换用汉字编码字符集·基本集》,项目代号为GB 2312 或 GB 2312-80(GB为国标汉语拼音的首字母),此套字符集于当年的5月1日起正式实施。

我们不客气地把那些127号之后的奇异符号们直接取消掉, 规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约 7000 多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,共包含7445个字符,6763个汉字和682个其他字符(拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母)。连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。可以认为 GB2312 是对 ASCII 的中文扩展。

GB2312是基于区位码设计的,在区位码的区号和位号上分别加上A0H就得到了GB2312编码,那么区位码是什么呢?

区位码:就是把中文常用的符号,数字,汉字等分门别类进行编码。区位码把编码表分为94个区,每个区对应94个位,每个位置就放一个字符(汉字,符号,数字都属于字符)。这样每个字符的区号和位号组合起来就成为该汉字的区位码。区位码一般用10进制数来表示,如4907就表示49区7位,对应的字符是“学”。区位码中01-09区是符号、数字区,16-87区是汉字区,10-15和88-94是未定义的空白区。它将收录的汉字分成两级:第一级是常用汉字计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺序排列。在网上搜索“区位码查询系统”可以很方便的找到汉字和对应区位码转换的工具。

中国国家标准总局把中文常用字符编码为94个区,每个区对应94个位,每个字符的区号和位号组合起来就是该字符的区位码, 区位码用10进制数来表示,如4907就表示49区7位,对应的字符是“学”。 由于区位码的取值范围与通信使用的控制码(00H~1FH)(即0~31)发生冲突。每个汉字的区号和位号分别加上32(即16进制20H)得到国标码,交换码。“学”的国标码为5127H。由于文本中通常混合使用汉字和西文字符,为了让汉字信息不会与单字节的ASCII码混淆,将一个汉字看成是两个扩展ASCII码,即汉字的两个字节的最高位置为1,得到的编码为GB2312汉字的内码。“学”的内码为D1A7H。无论你使用什么输入法,通过什么样的按键组合把“学”输入计算机,“学”在使用GB2312(以及兼容GB2312)编码的计算机里的内码都是D1A7H。

BIG5

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

GBK

1995年,中国教育科研网(NCFC)与美国NCFnet直接联网,这一天是中国被国际承认为开始有网际网路的时间。此后网络正式开始在中国大陆接通,个人计算机开始在中国流行。

GB2312的出现基本满足了汉字的计算机处理需要,但由于上面提到未收录繁体字和生僻字,从而不能处理人名、古汉语等方面出现的罕用字,这导致了1995年《汉字编码扩展规范》(GBK)的出现。GBK编码是GB2312编码的超集,向下完全兼容GB2312((GBK 包括了 GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号共收录21886个字符, 其中汉字21003个,字符883个)),兼容的含义是不仅字符兼容,而且相同字符的编码也相同,同时在字汇一级支持ISO/IEC10646—1和GB 13000—1的全部中、日、韩(CJK)汉字,共计20902字。GBK还收录了GB2312不包含的汉字部首符号、竖排标点符号等字符。CP936和GBK的有些许差别,绝大多数情况下可以把CP936当作GBK的别名。

GB18030

中国有56个民族,其中有12个民族有自己的文字,于是我们再扩展,又加了几千个新的少数民族的字,GBK 扩成了 GB18030。GBK和GB2312都是双字节等宽编码,如果算上和ASCII兼容所支持的单字节,也可以理解为是单字节和双字节混合的变长编码。GB18030编码是变长编码,有单字节、双字节和四字节三种方式。

在2000年,电子工业标准化研究所起草了GB18030标准,项目代号“GB 18030-2000”,全称《信息技术-信息交换用汉字编码字符集-基本集的扩充》。此标准推出后,在中国大陆之后的所售产品必须强制支持GB18030标准(GB18030收录了GBK中的所有字符,并将Unicode中其他中文字符(少数民族文字、偏僻字)也一并收录进来重新编码。其中GB 18030-2000共收录27533个汉字,而GB 18030-2005共包含70244个汉字)。从此之后,中华民族的文化就可以在计算机时代中传承了。

中国的程序员们看到这一系列汉字编码的标准是好的,于是通称他们叫做 “DBCS“(Double Byte Charecter Set 双字节字符集)。在DBCS系列标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,因此他们写的程序为了支持中文处理,必须要注意字串里的每一个字节的值,如果这个值是大于127的,那么就认为一个双字节字符集里的字符出现了。

小实验

od 查看文件内容:http://www.gnu.org/software/coreutils/manual/html_node/od-invocation.html
iconv 编码转换工具:http://www.gnu.org/software/libiconv/
汉字 Unicode(ucs-2)10进制表示 Utf-8 Utf-16 Utf32 区位码 GB2312/GBK/GB18030
中 20013 E4 B8 AD 4E2D 00004E2D 5448 D6D0
文 25991 E6 96 87 6587 00006587 4636 CEC4
机器环境:
os: Red Hat Enterprise Linux AS release 4
Cpu: Intel(R) Xeon(R) CPU
locale:LC_ALL=zh_CN.utf-8
//生成utf8编码下的文件
echo –n "中文" > foo.utf8
//检查foo的内容:
od -t x1 foo.utf8
0000000 e4 b8 ad e6 96 87
//转换为utf16编码
iconv -f utf-8 -t utf-16 foo.utf8 > foo.utf16
//查看foo.utf16内容
od -t x1 foo.utf16
0000000 ff fe 2d 4e 87 65
Ff fe是BOM(还记得吗?通过BOM来字节流的字节序),其余部分的确是UTF-16LE编码的内容
//转换为utf32编码
iconv -f utf-16 -t utf-32 foo.utf16 > foo.utf32
//查看foo.utf32内容
od -t x1 foo.utf32
0000000 ff fe 00 00 2d 4e 00 00 87 65 00 00
Ff fe是BOM,的确是UTF-32LE编码的内容
//转换为gb2312编码
iconv -f utf-8 -t gb2312 foo.txt > foo.gb2312
od -t x1 foo.gb2312
0000000 d6 d0 ce c4
//转换为GBK编码
iconv -f utf-8 -t gbk foo.txt > foo.gbk
od -t x1 foo.gbk
0000000 d6 d0 ce c4
//转换为GB18030编码
iconv -f utf-8 -t gb18030 foo.txt > foo.gb18030
od -t x1 foo.gb18030
0000000 d6 d0 ce c4

2.1.6 Emoji

绘文字(日语:絵文字/えもじ emoji)是日本在无线通信中所使用的视觉情感符号(图画文字),绘意指图形,文字则是图形的隐喻,可用来代表多种表情,如笑脸表示笑、蛋糕表示食物等。

第一个表情符号是由栗田穰崇于1998年或1999年创造,他当时隶属于NTT DoCoMo公司i-mode移动互联网平台的团队。第一套表情符号包括172个12×12像素的图标,设计初衷是作为i-mode消息功能的一部分帮助促进电子通讯,并作为区别于其他业务的特色功能。 然而在1997年,Nicolas Loufrani 注意到,ASCII表情符号在移动技术中的使用正在增加,他开始尝试动画效果的笑脸表情,目的是使用纯标点符号设计一套与现有ASCII表情对应的彩色图标,以促进其在数字领域的使用。Loufrani由此创造了第一套图形化表情,并编译了在线表情符号词典, 将这些符号分成不同类别,包括:经典类、情绪类、旗标类、庆贺类、娱乐类、体育类、天气类、动物类、饮食类、民族类、职业类、行星类、星座类、婴儿类等,这些设计最初于1997年在美国版权局注册,随后全套图标于1998年以.gif格式文件在网络上发布,成为科技行业中使用的第一套图形化表情符号。2000年,Loufrani创建的表情目录开始提供下载,用户开始可从互联网上通过smileydictionary.com为手机下载Loufrani创建的表情目录,该目录编译了超过1000个笑脸图形表情符号及其ASCII版本。该目录在2002年由Marabout以书籍形式出版,名称为Dico Smileys。2001年,表情符号公司Smiley Company 开始向各家电信公司的手机提供Loufrani图形表情符号的授权下载,这些公司包括诺基亚、摩托罗拉、三星、SFR(沃达丰)和SkyTelemedia。其中,“😂”(中文:喜极而泣的笑脸,英语:Face with Tears of Joy,Unicode码位:U+1F602)被《牛津词典》评选为2015年度词汇

在 NTT DoCoMo(日本三大电信运营商之一)的i-mode系统电话系统中,绘文字的尺寸是12x12 像素,在传送时,一个图形有2个字节。Unicode编码为E63E到E757。基本的绘文字共有176个符号,在C-HTML4.0的编程语言中,则另增添了76个情感符号。

总结

TODO

捧个钱场?