国际社会编码标准-战国时代
在二十世纪60年代至90年代这三十多年中,出现了多个不同的计算机编码标准。
如:
- 1968年由美国国家标准学会(ANSI)发布的ASCII(美国信息交换标准代码)是最早的字符编码标准之一。
- ASCII是单字节编码,最多支持128个字符,包括英文字母(大小写)、数字、标点符号和控制字符。
- 它主要用于英语和其他使用拉丁字母的西欧语言,但无法支持带重音符号的字符(如法语的é)。
- 为解决ASCII无法支持欧洲语言字符的问题,国际标准化组织(ISO)和国际电工委员会(IEC)制定了ISO/IEC 8859标准。
- ISO/IEC 8859是一组单字节编码,前128个字符与ASCII一致,后128个字符用于扩展字符。
- 由于128个扩展字符的存在,所以ISO8859有多个不同的版本用于支持欧洲的各种语言。
- 1982年,ASCII公司(当时微软在日本的子公司)首次提出了Shift-JIS的概念,并将其应用于CP/M-86操作系统。随后,微软、ASCII、IBM和三菱电机等公司共同推动了这一编码方案的标准化。
- 1997年,Shift-JIS被正式纳入日本工业标准(JIS X 0208),进一步巩固了其在日本计算机领域的地位。
- 1988年,Andrey Chernov整理出了KOI8-R并提交给互联网协会,成为RFC 1489文件。这是KOI-8系列的第一个版本,专门为俄语设计,是最广泛使用的西里尔字母编码之一。
在Unicode出现之前,国际上存在多种编码方案,主要用于满足不同语言和地区的需求,以上这些编码在当时各自所在的语言社区均有极大的使用率。
然而,这些编码方案之间互不兼容,导致了信息交换的复杂性。Unicode的出现正是为了解决这些问题,通过统一字符集和编码方式,支持全球所有语言的字符。
Unicode的发展
由来
1988年,统一码联盟(Unicode Consortium)和国际标准化组织(ISO)分别制定了Unicode和ISO/IEC 10646标准。后来发现双方的目标一致,于是在1991年开始合作,将两个标准合并。
从Unicode2.0版本开始,Unicode与ISO/IEC 10646标准保持同步,统一了字符集和编码方案。
Unicode的目标是为世界上所有语言的每个字符分配一个唯一的数字编码,从而实现跨语言、跨平台的文本转换和处理。它采用16位、32位及更多位的编码单元来表示字符,支持多种编码方案,如UTF-8、UTF-16和UTF-32。
Unicode的首次正式发布是在1994年,当时包含7,161个字符。此后,Unicode不断扩展和更新,截至2024年9月,最新版本为16.0.0,共收录了154,998个字符。
对于这么多字符,Unicode 将它们分成了17 组进行编排,每组称为平面,每个平面拥有 65536(2 的 16 次方)个码点。
所有最常见的字符都放在 0 号平面,称为基本多语言平面(BMP),码点范围从 U+0000 到 U+FFFF,共有 65536 个字符。剩下的平面称为辅助平面,码点范围从 U+010000 到 U+10FFFF。
编码方式
Unicode 支持多种编码形式,包括 UTF-8、UTF-16 和 UTF-32,以适应不同的存储和传输需求。
- UTF-8:可变长编码,字符长度为1到4字节。ASCII字符在UTF-8中保持不变(占用1字节),而其他字符根据需要占用更多字节。
- UTF-16:可变长编码,字符长度为2或4字节。
- UTF-32:固定长度编码,每个字符占用4字节。字节内容与码点的数值完全相同一致。
- 好处是UTF-32的编码并不需要特殊处理,查找效率高。
- 坏处是无论码点大小,都使用了四字节,尤其常用字符都是小码点,空间浪费极大。
UTF-8
| 字节数 | Unicode 字符码点范围(十六进制) | 码点位数 | 字节1 | 字节2 | 字节3 | 字节4 |
|---|---|---|---|---|---|---|
| 1 | U+0000 ~ U+007F | 7 | 0xxxxxxx | |||
| 2 | U+0080 ~ U+07FF | 11 | 110xxxxx | 10xxxxxx | ||
| 3 | U+0800 ~ U+FFFF | 16 | 1110xxxx | 10xxxxxx | 10xxxxxx | |
| 4 | U+10000 ~ U+10FFFF | 21 | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
规则:
1、确定码点范围获得该码点的字节数和默认字节规则
2、将码点转换为二进制数
3、依次塞入默认字节规则的X中,这样就获得了该码点UTF-8编码方式的二进制编码
举例:
1、“且”的码点为U+4E14,二进制数为0100 111000 010100
2、由范围可知,该字符为3字节长度,所以使用 1110XXXX 10XXXXXX 10XXXXXX的默认字节规则
3、将码点二进制对应塞入字节规则中,得到11100100 10111000 10010100
4、十六进制就得到了0xE4 0xB8 0x94
问题:在只有一堆字符形成的二进制数的集合中,如何判断一个字符是多少字节长度?
UTF-16
| 字节数 | Unicode 字符码点范围(十六进制) |
|---|---|
| 2 | U+0000 ~ U+D7FF |
| 2 | U+E000 ~ U+FFFF |
| 4 | U+10000 ~ U+10FFFF |
在基本多语言平面的码点字符,范围是U+0000 ~ U+FFFF,其码点与UTF-16的编码完全一致。
在辅助平面的码点字符,范围是U+10000 ~ U+10FFFF,需要使用4个字节来表示。
那么在实际使用中,会出现一个问题就是,我怎么确定当前的两个字节是独自用来表示一个字符,还是与后面两个字节一起表示一个字符?
这个问题,在unicode的设计时就已经考虑过了,在基本多语言平面,存在一个范围U+D800 ~ U+DFFF,叫代理对。而UTF-16的四字节编码就是通过代理对来表示的。
代理对由两个 2 字节的代码组成:高代理(high surrogate)和低代理(low surrogate)。
高代理范围:D800 到 DBFF。
低代理范围:DC00 到 DFFF。
规则:
1、码点减去 0x10000,得到的值用 20 个二进制位表示(不足在前面补 0 )。
2、将前 10 个二进制位加上 0xD800 得到高位代理。
3、将后 10 个二进制位加上 0xDC00 得到低位代理。
举例:
1、“𒀁”(楔形文字)的码点为U+12001,码点减去 0x10000得到的十六进制0x2001,二进制数为
0000001000 0000000001
2、将前10个二进制位加上0xD800得到高位代理 0xD808
3、将后10个二进制位加上0xDC00得到低位代理 0xDC01
4、那么“𒀁”的UTF-16编码就是0xD808 0xDC01了
字节序问题
源于计算机体系结构的差异。
字节序分两种,大端序和小端序:
- 大端序(Big-Endian,BE):高字节存储在低地址,低字节存储在高地址。
- 例如,16 位数值 0x1234 在内存中存储为:12(低地址)34(高地址)。
- 小端序(Little-Endian,LE):低字节存储在低地址,高字节存储在高地址。
- 例如,16 位数值 0x1234 在内存中存储为:34(低地址)12(高地址)。
例如:
- 大端序系统:如网络协议(TCP/IP)、Java 字节码、某些 RISC 架构(如 MIPS)。
- 小端序系统:如 x86 架构(Windows、Linux)、ARM 架构(小端模式)。
如何解决字节序问题
为了确保 UTF-16 数据在不同系统之间能够正确解析,引入了字节序标记(Byte Order Mark,BOM)。
BOM 是一个特殊的 Unicode 字符(U+FEFF),用于指示数据的字节序。
大端序(BE):BOM 的字节序为 FE FF。
小端序(LE):BOM 的字节序为 FF FE。
通过在数据流或文件的开头放置 BOM,接收方可以检测到数据的字节序,并正确解析后续内容。
UTF-32会不会有字节序的问题?UTF-8会不会有字节序的问题?
中文圈的编码标准
繁体中文-Big5
背景
当时个人电脑没有共通的编码标准,导致厂商推出的中文应用软件无法推广,并且与IBM 5550、王安码等内码,彼此不能兼容。同时,台湾地区迟迟未能推出中文编码标准。
台湾官方的标准是CNS11643,最初版本的发布时间是1986年。
发展
台湾财团法人信息产业策进会以CNS11643的早期版本为基础,在1984年公布的编码标准。初始用途是为了制作“五大中文套装软件”,但最终结果是该软件套装并未取代国外的软件,反而是编码标准在繁体中文社区大获成功。
所以在繁体中文社区盛行的反而是非官方标准的Big5。
趣事
1980年9月台湾行政院国家科学委员会联合各方编码专家开始推进编码标准的进行,直到1986年公布,取名为“通用汉字标准交换码”(UCS),此时共有13,051字。
1992年扩充至48,027字,并改称“中文标准交换码”(CSIC)。
2004年更名为“CNS11643”。
本来是以此为替代品,替换当时已经风靡繁体中文社区的Big5编码标准,但没能成功。
主要原因是该编码以三个字节表示一个字符会导致文字无法对齐,而用两个字节来表示一个中文字符则不会出现这样的问题。所以当时的中文开发者偏爱Big5。
结局
同样可能也因为是非官方标准,所以各厂商及政府推出的Big5延伸,彼此互不兼容,会造成乱码问题。在现代操作系统和软件的开发上,已经开始抛弃Big5,转而拥抱unicode了。
不过更大的因素可能还是因为unicode能支持七万多个汉字以及其他语言。
简体中文-GB2312、GBK、GB18030
GB2312:最初的国家标准
由来:八十年代,没有任何编码标准是支持中文的,所以为了在计算机领域不被拉开差距。中国国家标准总局在1980年公布了GB2312,并在1981年开始正式实施。
特点:
- 采用双字节编码,共收录6763个汉字和682个符号,基本满足了当时简体中文的使用需求。
- 兼容ASCII码,使得汉字与英文字符能够共存
局限性:
GB2312共收录了6763个简体汉字,其中一级汉字3755个(按拼音排序),二级汉字3008个(按偏旁部首排序),覆盖了中国大陆99.75%的使用频率。但不支持其他语言以及一些中文生僻字。
所以本质上,GB2312和它同时间出现的编码标准一样,存在同样的问题就是无法跨语言交换数据。
GBK:对GB2312的扩展
GBK是由中国电子工业标准化技术协会(CESA)组织制定的扩展汉字编码标准。于1995年发布。
特点:
- GBK是对GB2312的扩展,增加了近20000个新的汉字和符号,包括繁体字、生僻字和多种语言字符。
- 完全向下兼容GB2312,同时也向上支持 ISO 10646.1国际标准。
- GBK同样也采用双字节编码。
GB18030:国家标准的全面覆盖
GB18030由全国信息技术标准化技术委员会(TC28)归口管理,主要起草单位包括中国电子技术标准化研究院、北京北大方正电子有限公司、微软(中国)有限公司等。
特点:
- 新增了中国少数民族的语言字符,如:藏文、规范彝文、朝鲜文、维哈柯文、蒙古文、滇东北苗文、傈僳文、西双版纳新傣文、西双版纳老傣文、德宏傣文。
- 新增了中国绝大部分人名、地名用生僻字以及文献、科技等专业领域的用字。
- 采用多字节编码,每个字符可以由1个、2个或4个字节组成。
- 兼容GB2312和GBK,同时支持Unicode的全部字符。