共计 8819 个字符,预计需要花费 23 分钟才能阅读完成。
本文由阮一峰(ruanyifeng.com)分享,本文收录时有内容订正和排版优化。
1、引言
明天中午,我忽然想搞清楚 Unicode 和 UTF-8 之间的关系,就开始查资料。这个问题比我设想的简单,午饭后始终看到早晨 9 点,才算初步搞清楚。上面就是我的总结,次要用来整顿本人的思路。我尽量写得通俗易懂,心愿能对其余敌人有用。毕竟,字符编码是计算机技术的 * 石,对于程序员来说尤其重要,字符编码的常识是必须要懂的。
技术交换:
- 挪动端 IM 开发入门文章:《新手入门一篇就够:从零开发挪动端 IM》
- 开源 IM 框架源码:https://github.com/JackJiang2011/MobileIMSDK(备用地址点此)
(本文已同步公布于:http://www.52im.net/thread-4433-1-1.html)
2、专题目录
本文是“字符编码技术专题”系列文章的第 1 篇,总目录如下:
《字符编码技术专题(一):疾速了解 ASCII、Unicode、GBK 和 UTF-8》(* 本文)
《字符编码技术专题(二):史诗级计算机字符编码常识入门,一文即懂!》
《字符编码技术专题(三):彻底搞懂字符乱码的实质,一篇就够!》
《字符编码技术专题(四):史上最艰深大小端字节序详解,一文即懂!》
《字符编码技术专题(五):前端必读的计算机字符编码常识入门》
3、基础知识
计算机中贮存的信息都是用二进制数示意的;而咱们在屏幕上看到的英文、汉字等字符是二进制数转换之后的后果。艰深的说,依照何种规定将字符存储在计算机中,如 ’a’ 用什么示意,称为 ” 编码 ”;反之,将存储在计算机中的二进制数解析显示进去,称为 ” 解码 ”,如同密码学中的加密和解密。在解码过程中,如果应用了谬误的解码规定,则导致 ’a’ 解析成 ’b’ 或者乱码。
字符集(Charset):是一个零碎反对的所有形象字符的汇合。字符是各种文字和符号的总称,包含各国家文字、标点符号、图形符号、数字等。
字符编码(Character Encoding):是一套法令,应用该法令可能对自然语言的字符的一个汇合(如字母表或音节表),与其余货色的一个汇合(如号码或电脉冲)进行配对。即在符号汇合与数字零碎之间建设对应关系,它是信息处理的一项 本技术。通常人们用符号汇合(个别状况下就是文字)来表白信息。而以计算机为 础的信息处理系统则是利用元件(硬件)不同状态的组合来存储和解决信息的。元件不同状态的组合能代表数字零碎的数字,因而字符编码就是将符号转换为计算机能够承受的数字零碎的数,称为数字代码。
常见字符集名称:ASCII 字符集、GB2312 字符集、BIG5 字符集、GB18030 字符集、Unicode 字符集等。计算机要精确的解决各种字符集文字,须要进行字符编码,以便计算机可能辨认和存储各种文字。
4、ASCII 码
咱们晓得,计算机外部,所有信息最终都是一个二进制值。每一个二进制位(bit)有 0 和 1 两种状态,因而八个二进制位就能够组合出 256 种状态,这被称为一个字节(byte)。也就是说,一个字节一共能够用来示意 256 种不同的状态,每一个状态对应一个符号,就是 256 个符号,从 00000000 到 11111111。上个世纪 60 年代,美国制订了一套字符编码,对英语字符与二进制位之间的关系,做了对立规定。这被称为 ASCII 码,始终沿用至今。ASCII 码一共规定了 128 个字符的编码,比方空格 SPACE 是 32(二进制 00100000),大写的字母 A 是 65(二进制 01000001)。这 128 个符号(包含 32 个不能打印进去的管制符号),只占用了一个字节的前面 7 位,最后面的一位对立规定为 0。
▲ ASCII 编码表
5、非 ASCII 编码
英语用 128 个符号编码就够了,然而用来示意其余语言,128 个符号是不够的。比方,在法语中,字母上方有注音符号,它就无奈用 ASCII 码示意。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比方,法语中的é的编码为 130(二进制 10000010)。这样一来,这些欧洲国家应用的编码体系,能够示意最多 256 个符号。
▲ 扩大 ASCII 编码表然而,这里又呈现了新的问题。不同的国家有不同的字母,因而,哪怕它们都应用 256 个符号的编码方式,代表的字母却不一样。比方,130 在法语编码中代表了é,在希伯来语编码中却代表了字母 Gimel (ג),在俄语编码中又会代表另一个符号。然而不管怎样,所有这些编码方式中,0–127 示意的符号是一样的,不一样的只是 128–255 的这一段。至于亚洲国家的文字,应用的符号就更多了,汉字就多达 10 万左右。一个字节只能示意 256 种符号,必定是不够的,就必须应用多个字节表白一个符号。比方,简体中文常见的编码方式是 GB2312,应用两个字节示意一个汉字,所以实践上最多能够示意 256 x 256 = 65536 个符号。中文编码的问题比较复杂,将在文末探讨。这里先理解下,尽管都是用多个字节示意一个符号,然而 GB 类的汉字编码与后文的 Unicode 和 UTF-8 是毫无关系的。
6、Unicode
正如上一节所说,世界上存在着多种编码方式,同一个二进制数字能够被解释成不同的符号。因而,要想关上一个文本文件,就必须晓得它的编码方式,否则用谬误的编码方式解读,就会呈现乱码。为什么电子邮件经常呈现乱码?就是因为发信人和收信人应用的编码方式不一样。能够设想,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个举世无双的编码,那么乱码问题就会隐没。这就是 Unicode,就像它的名字都示意的,这是一种所有符号的编码。Unicode 当然是一个很大的汇合,当初的规模能够包容 100 多万个符号。每个符号的编码都不一样,比方,U+0639 示意阿拉伯字母 Ain,U+0041 示意英语的大写字母 A,U+4E25 示意汉字严。具体的符号对应表,能够查问 unicode.org,或者专门的汉字对应表。
7、Unicode 的问题
须要留神的是,Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。比方,汉字严的 Unicode 是十六进制数 4E25,转换成二进制数足足有 15 位(100111000100101),也就是说,这个符号的示意至多须要 2 个字节。示意其余更大的符号,可能须要 3 个字节或者 4 个字节,甚至更多。这里就有两个重大的问题,第一个问题是,如何能力区别 Unicode 和 ASCII?计算机怎么晓得三个字节示意一个符号,而不是别离示意三个符号呢?第二个问题是,咱们曾经晓得,英文字母只用一个字节示意就够了,如果 Unicode 对立规定,每个符号用三个或四个字节示意,那么每个英文字母前都必然有二到三个字节是 0,这对于存储来说是极大的节约,文本文件的大小会因而大出二三倍,这是无奈承受的。它们造成的后果是:1)呈现了 Unicode 的多种存储形式,也就是说有许多种不同的二进制格局,能够用来示意 Unicode。2)Unicode 在很长一段时间内无奈推广,直到互联网的呈现。
8、UTF-8
互联网的遍及,强烈要求呈现一种对立的编码方式。UTF-8 就是在互联网上应用最广的一种 Unicode 的实现形式。其余实现形式还包含 UTF-16(字符用两个字节或四个字节示意)和 UTF-32(字符用四个字节示意),不过在互联网上 * 本不必。反复一遍,这里的关系是,UTF-8 是 Unicode 的实现形式之一。UTF-8 最大的一个特点,就是它是一种变长的编码方式。它能够应用 1~4 个字节示意一个符号,依据不同的符号而变动字节长度。
UTF-8 的编码规定很简略,只有二条:
1)对于单字节的符号:字节的第一位设为 0,前面 7 位为这个符号的 Unicode 码。因而对于英语字母,UTF-8 编码和 ASCII 码是雷同的;
2)对于 n 字节的符号(n > 1):第一个字节的前 n 位都设为 1,第 n + 1 位设为 0,前面字节的前两位一律设为 10。剩下的没有提及的二进制位,全副为这个符号的 Unicode 码。
下表总结了编码规定,字母 x 示意可用编码的位:
跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是 0,则这个字节独自就是一个字符;如果第一位是 1,则间断有多少个 1,就示意以后字符占用多少个字节。上面,还是以汉字严为例,演示如何实现 UTF-8 编码。严的 Unicode 是 4E25(100111000100101),依据上表,能够发现 4E25 处在第三行的范畴内(0000 0800 – 0000 FFFF),因而严的 UTF-8 编码须要三个字节,即格局是 1110xxxx 10xxxxxx 10xxxxxx。而后,从严的最初一个二进制位开始,顺次从后向前填入格局中的 x,多出的位补 0。这样就失去了,严的 UTF-8 编码是 11100100 10111000 10100101,转换成十六进制就是 E4B8A5。
9、Unicode 与 UTF-8 之间的转换
通过上一节的例子,能够看到严的 Unicode 码 是 4E25,UTF-8 编码是 E4B8A5,两者是不一样的。它们之间的转换能够通过程序实现。Windows 平台,有一个最简略的转化办法,就是应用内置的记事本小程序 notepad.exe。关上文件后,点击文件菜单中的另存为命令,会跳出一个对话框,在最底部有一个编码的下拉条。
外面有四个选项:ANSI,Unicode,Unicode big endian 和 UTF-81)ANSI 是默认的编码方式:对于英文文件是 ASCII 编码,对于简体中文文件是 GB2312 编码(只针对 Windows 简体中文版,如果是繁体中文版会采纳 Big5 码);2)Unicode 编码这里指的是 notepad.exe 应用的 UCS-2 编码方式:即间接用两个字节存入字符的 Unicode 码,这个选项用的 little endian 格局;3)Unicode big endian 编码与上一个选项绝对应:我在下一节会解释 little endian 和 big endian 的涵义;4)UTF- 8 编码:也就是上一节谈到的编码方法。抉择完 ” 编码方式 ” 后,点击 ” 保留 ” 按钮,文件的编码方式就立即转换好了。
10、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 标准定义,每一个文件的最后面别离退出一个示意编码程序的字符,这个字符的名字叫做 ” 零宽度非换行空格 ”(zero width no-break space),用 FEFF 示意。这正好是两个字节,而且 FF 比 FE 大 1。如果一个文本文件的头两个字节是 FE FF,就示意该文件采纳大头形式;如果头两个字节是 FF FE,就示意该文件采纳小头形式。
11、实例解说
上面,举一个实例。关上 ” 记事本 ” 程序 notepad.exe,新建一个文本文件,内容就是一个严字,顺次采纳 ANSI,Unicode,Unicode big endian 和 UTF- 8 编码方式保留。而后,用文本编辑软件 UltraEdit 中的 ” 十六进制性能 ”,察看该文件的外部编码方式:1)ANSI:文件的编码就是两个字节 D1 CF,这正是严的 GB2312 编码,这也暗示 GB2312 是采纳大头形式存储的。2)Unicode:编码是四个字节 FF FE 25 4E,其中 FF FE 表明是小头形式存储,真正的编码是 4E25。3)Unicode big endian:编码是四个字节 FE FF 4E 25,其中 FE FF 表明是大头形式存储。4)UTF-8:编码是六个字节 EF BB BF E4 B8 A5,前三个字节 EF BB BF 示意这是 UTF- 8 编码,后三个 E4B8A5 就是严的具体编码,它的存储程序与编码程序是统一的。UltraEdit 下载地址请至官网:https://www.ultraedit.com/
▲ UltraEdit 软件
12、最初简要看看中文字符集和编码
12.1GB 系列字符集 & 编码
计算机创造之处及前面很长一段时间,只用利用于美国及东方一些发达国家,ASCII 可能很好满足用户的需要。然而当天朝也有了计算机之后,为了显示中文,必须设计一套编码规定用于将汉字转换为计算机能够承受的数字零碎的数。天朝专家把那些 127 号之后的奇怪符号们(即 EASCII)勾销掉,规定:一个小于 127 的字符的意义与原来雷同,但两个大于 127 的字符连在一起时,就示意一个汉字,后面的一个字节(他称之为高字节)从 0xA1 用到 0xF7,前面一个字节(低字节)从 0xA1 到 0xFE,这样咱们就能够组合出大概 7000 多个简体汉字了。在这些编码里,还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在 ASCII 里原本就有的数字、标点、字母都通通从新编了两个字节长的编码,这就是常说的 ” 全角 ” 字符,而原来在 127 号以下的那些就叫 ” 半角 ” 字符了。上述编码规定就是 GB2312。GB2312 或 GB2312-80 是中国国家标准简体中文字符集,全称《信息替换用汉字编码字符集·本集》,又称 GB0,由中国国家标准总局公布,1981 年 5 月 1 日施行。GB2312 编码通行于中国大陆;新加坡等地也采纳此编码。中国大陆简直所有的中文系统和国际化的软件都反对 GB2312。GB2312 的呈现,本满足了汉字的计算机解决须要,它所收录的汉字曾经笼罩中国大陆 99.75% 的应用频率。对于人名、古汉语等方面呈现的罕用字,GB2312 不能解决,这导致了起初 GBK 及 GB 18030 汉字字符集的呈现。
下图是 GB2312 编码的开始局部(因为其十分宏大,只列举开始局部,具体可查看 GB2312 简体中文编码表)。
▲ GB2312 编码表的开始局部
因为 GB 2312-80 只收录 6763 个汉字,有不少汉字,如局部在 GB 2312-80 推出当前才简化的汉字(如 ” 啰 ”),局部人名用字(如中国前总理 * 的 ”*” 字),台湾及香港应用的繁体字,日语及朝鲜语汉字等,并未有收录在内。于是厂商微软利用 GB 2312-80 未应用的编码空间,收录 GB 13000.1-93 全副字符制订了 GBK 编码。依据微软材料,GBK 是对 GB2312-80 的扩大,也就是 CP936 字码表 (Code Page 936)的扩大(之前 CP936 和 GB 2312-80 截然不同),最早实现于 Windows 95 简体中文版。尽管 GBK 收录 GB 13000.1-93 的全副字符,但编码方式并不相同。GBK 本身并非国家标准,只是曾由国家技术监督局标准化司、电子工业部科技与品质监督司颁布为 ” 技术规范指导性文件 ”。原始 GB13000 始终未被业界采纳,后续国家标准 GB18030 技术上兼容 GBK 而非 GB13000。
GB 18030,全称:国家标准 GB 18030-2005《信息技术 中文编码字符集》,是中华人民共和国现时最新的内码字集,是 GB 18030-2000《信息技术 信息替换用汉字编码字符集 本集的裁减》的修订版。与 GB 2312-1980 齐全兼容,与 GBK本兼容,反对 GB 13000 及 Unicode 的全副对立汉字,共收录汉字 70244 个。GB 18030 次要有以下特点:与 UTF- 8 雷同,采纳多字节编码,每个字能够由 1 个、2 个或 4 个字节组成;编码空间宏大,最多可定义 161 万个字符;反对中国国内少数民族的文字,不须要动用造字区;汉字收录范畴蕴含繁体汉字以及日韩汉字。
▲ GB18030 编码总体构造
本规格的初版使中华人民共和国信息产业部电子工业标准化研究所起草,由国家质量技术监督局于 2000 年 3 月 17 日公布。现行版本为国家品质监督测验总局和中国国家标准化治理委员会于 2005 年 11 月 8 日公布,2006 年 5 月 1 日施行。此规格为在中国境内所有软件产品反对的强制规格。
12.2BIG5 字符集 & 编码
Big5,又称为大五码或五大码,是应用繁体中文(正体中文)社区中最罕用的电脑汉字字符集规范,共收录 13,060 个汉字。中文码分为内码及替换码两类,Big5 属中文内码,出名的中文替换码有 CCCII、CNS11643。Big5 虽遍及于台湾、香港与澳门等繁体中文通行区,但长期以来并非当地的国家标准,而只是业界规范。倚天中文系统、Windows 等次要零碎的字符集都是以 Big5 为 * 准,但厂商又各自减少不同的造字与造字区,派生成多种不同版本。2003 年,Big5 被收录到 CNS11643 中文规范替换码的附录当中,获得了较正式的位置。这个最新版本被称为 Big5-2003。Big5 码是一套双字节字符集,应用了双八码存储办法,以两个字节来安放一个字。第一个字节称为 ” 高位字节 ”,第二个字节称为 ” 低位字节 ”。” 高位字节 ” 应用了 0x81-0xFE,” 低位字节 ” 应用了 0x40-0x7E,及 0xA1-0xFE。无关 Big5 的更多技术细节读者可独自深入研究,本文就不赘述了。
13、本文小结
这些字符集和编码的关系很容易让程序员混同,当初小结一下。简略来说:Unicode、GBK 和 Big5 码等就是编码的值(也就是术语“字符集”),而 UTF-8、UTF-16、UTF32 之类就是这个值的表现形式(即术语“编码格局”)。另外:Unicode、GBK 和 Big5 码等字符集是不兼容的,同一个汉字在这三个字符集里的码值是齐全不一样的。如"汉"的 Unicode 值与 gbk 就是不一样的,假如 Unicode 为 a040,GBK 为 b030。以 UTF- 8 为例,UTF- 8 码齐全只针对 Unicode 来组织的,如果 GBK 要转 UTF- 8 必须先转 Unicode 码,再转 UTF- 8 就 OK 了。
即 GBK、GB2312 等与 UTF8 之间都必须通过 Unicode 编码能力互相转换:
1)GBK、GB2312 – 先转 –> Unicode – 再转 –> UTF8
2)UTF8 – 先转 –> Unicode – 再转 –> GBK、GB2312
附录:更多 IM 技术精髓文章
[1] 新手入门一篇就够:从零开发挪动端 IM》
[2] 零 * 础 IM 开发入门(一):什么是 IM 零碎?》
[3] 零 * 础 IM 开发入门(二):什么是 IM 零碎的实时性?》
[4] 零 * 础 IM 开发入门(三):什么是 IM 零碎的可靠性?》
[5] 零 * 础 IM 开发入门(四):什么是 IM 零碎的音讯时序一致性?》
[6] 挪动端 IM 开发者必读(一):通俗易懂,了解挪动网络的“弱”和“慢”》
[7] 挪动端 IM 开发者必读(二):史上最全挪动弱网络优化办法总结》
[8] 从客户端的角度来谈谈挪动端 IM 的音讯可靠性和送达机制》
[9] 古代挪动端网络短连贯的优化伎俩总结:申请速度、弱网适应、平安保障》
[10] 史上最艰深 Netty 框架入门长文:* 本介绍、环境搭建、入手实战
[11] 强列倡议将 Protobuf 作为你的即时通讯利用数据传输格局
[12] IM 通信协定专题学习(一):Protobuf 从入门到精通,一篇就够!
[13] 微信新一代通信安全解决方案:* 于 TLS1.3 的 MMTLS 详解
[14] 探讨组合加密算法在 IM 中的利用
[15] 从客户端的角度来谈谈挪动端 IM 的音讯可靠性和送达机制
[16] IM 音讯送达保障机制实现(一):保障在线实时音讯的牢靠投递
[17] 了解 IM 音讯“可靠性”和“一致性”问题,以及解决方案探讨
[18] 融云技术分享:全面揭秘亿级 IM 音讯的牢靠投递机制
[19] IM 群聊音讯如此简单,如何保障不丢不重?
[20] 零 * 础 IM 开发入门(四):什么是 IM 零碎的音讯时序一致性?
[21] 一套亿级用户的 IM 架构技术干货(下篇):可靠性、有序性、弱网优化等
[22] 如何保障 IM 实时音讯的“时序性”与“一致性”?
[23] 阿里 IM 技术分享(六):闲鱼亿级 IM 音讯零碎的离线推送达到率优化
[24] 微信的海量 IM 聊天音讯序列号生成实际(算法原理篇)
[25] 社交软件红包技术解密(一):全面解密 QQ 红包技术计划——架构、技术实现等
[26] 网易云信技术分享:IM 中的万人群聊技术计划实际总结
[27] 企业微信的 IM 架构设计揭秘:音讯模型、万人群、已读回执、音讯撤回等
[28] 融云 IM 技术分享:万人群聊音讯投递计划的思考和实际
[29] 为何 * 于 TCP 协定的挪动端 IM 依然须要心跳保活机制?
[30] 一文读懂即时通讯利用中的网络心跳包机制:作用、原理、实现思路等
[31] 微信团队原创分享:Android 版微信后盾保活实战分享(网络保活篇)
[32] 融云技术分享:融云安卓端 IM 产品的网络链路保活技术实际
[33] 阿里 IM 技术分享(九):深度揭密 RocketMQ 在钉钉 IM 零碎中的利用实际
[34] 彻底搞懂 TCP 协定层的 KeepAlive 保活机制
[35] 深度解密钉钉即时消息服务 DTIM 的技术设计
[36] * 于实际:一套百万音讯量小规模 IM 零碎技术要点总结
[37] 跟着源码学 IM(十):* 于 Netty,搭建高性能 IM 集群(含技术思路 + 源码)
[38] 一套十万级 TPS 的 IM 综合音讯零碎的架构实际与思考(本文已同步公布于:
http://www.52im.net/thread-4433-1-1.html)