从编码模型角度理解字符编码

1,808 阅读28分钟

前言

什么是编码

编码是信息从一种形式或格式转换为另一种形式的过程,用预先规定的方法将文字、数字或其它对象编成数码,或将信息、数据转换成规定的电脉冲信号。 编码是信息从一种形式或格式转换为另一种形式的过程。解码,是编码的逆过程。

———《百度百科

为什么要有编码

编码的过程实际上可以理解为信息加工处理的过程,通过处理,可以更便捷有效的传播信息。

在早期,人们通过表情手势情绪的方式进行通信(信息交流),但这种通信方式传播的信息载量和传播距离都非常有限,对于信息的存储而言基本为零。随着人类群居社会的发展,这样的通信变得十分低效,于是人们便慢慢发展出其他的方式来提高人与人之间的通信。包括早期的结绳记事,以及后面逐渐形成的语言,这些可以看作最早的“编码”。人们将信息“编码”为语言(包括抽象文字符号和语音),通过声音、文字和图像的方式进行记录传播,而通过对相应语言和文化的学习使得我们能听懂语言读懂文字,进而将它们“解码”为真正的信息内容。

语言 是生物同类之间由于沟通需要而制定的具有统一编码解码标准的声音(图像)指令。实质定义语言是以声音/符号为物质外壳,以含义为内涵,由词汇和语法构成并能表达人类思想的指令系统。语音、手势、表情是语言在人类肢体上的体现,文字符号是语言的显像符号。

——— 《百度百科

此时传播的信息载量和距离相比之前有了极大的提升,而随着社会的不断发展和进步,我们进入了信息化时代,能利用的传输媒介开始增多,通信方式(例如网络、电话等)和通信对象(例如计算机之间的通信)也更加多元,此时所需要编码的内容以及编码的结果也越来越多样,但无论如何变化,本质还是为了使人的沟通更加便捷有效,编码的目的依旧是为了方便信息的存储,检索,使用和传播。只是在信息化社会时代,对信息的处理侧重于数据形式之间的转换,现在狭义上的编码就是指代这个过程。

对于计算机而言,针对不同的内容形式有各自对应的编码技术,例如文字相关的字符编码有ASCII Unicode GBK等,图像编码有jpg, png, webp等(图像编码侧重对图像的压缩处理),视频编码有real,mov,MPEG4, H.264等,音频编码有wav, aac, mp3等。接下来本文主要介绍与文字相关的字符编码。

字符编码

文字,或者说字符,是一个可以被人类识别的抽象化的图形符号,本质是图形,在计算机中称之为图元或者图形码。虽说广义上来说文字也是信息“编码”后的结果,但这种编码方案是人类文明的产物,计算机并不认识。对于计算机而言,它只认识有0、1组成的二进制数,为了使人能够和计算机通信,我们需要把人类可识别的抽象符号转换为计算机可识别的二进制数,再底层一点计算机需要将二进制数转换为电信号进行传播。于是就出现了字符编码,它的目的就是将抽象字符形式转换为二进制形式。

Untitled.png

字符编码(Character encoding)也称字集码,是把字符集中的字符,编码为指定集合中的某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储或者通信网络的传递。常见的例子是将拉丁字母表编码成摩斯电码和ASCII,比如ASCII编码是将字母、数字和其它符号进行编号,并用7比特的二进制来表示这个整数。

抽象字符与字形

关于字形和字符的区别,这里要简单说明一下。字形主要是视觉上的呈现,而一个抽象字符表示的含义在相应的文化背景下是有明确定义的,不会根据视觉表现形式的不同而产生区别。例如字母a,不同的字体会有不同的视觉呈现。而具体的视觉呈现是字体设计师关注的事,我们只关注抽象字符的映射关系。

Untitled 1.png

抽象字符和具体字形的映射,是通过字形库来进行关联的。例如在TTF中有字库表来进行关联。字库表(character repertoire)就是字符数据库,存储了字符集中所有字符(码点)与对应图元的映射关系。

通过Typr可以查看: 例如图中选中字形1 ,可以查看到对应的抽象字符是1 ,对应的Unicode码位是 0031

Untitled 2.png

字符编码标准

ASCII标准

💡 这里要提前说明一下,因为Unicode是不同的编码体系(下章介绍)。所以在Unicode标准之前,一些术语是有混淆概念的,所以在本节表达的字符编码标准(或者编码标准),也可以理解为字符集标准。

字符编码(character encoding),字符映射(character map),字符集(character set)或者代码页,在历史上往往是同义概念,即字符表(repertoire)中的字符如何编码为码元的流(stream of code units)–通常每个字符对应单个码元。 —— 《维基百科》

虽然有了字符编码,人们可以和计算机通信,使用计算机处理文本了,但此时遇到了一个问题。计算机最早发明出来是用来解决数学问题的,在互联网没有发明出来,它实际上就是一台普通计算机器,即使通过字符编码赋予了计算机处理文本的能力,但计算机之间并不能通信。

此时虽然大多数厂商都会给自己的产品赋予相应的能力,但底层的硬件和软件还都是各管各的,没有一个统一的标准,字符编码也是如此,这就导致了后来机器之间需要相互通信的时候,字符无法正确显示的问题。为了统一字符编码结果,保证计算机通信结果的准确性,美国有关的标准化组织(美国国家标准学会(American National Standard Institute,ANSI))就跑出来制定了ASCII编码 (American Standard Code for Information Interchange),统一了游戏规则,规定了常用符号用哪些二进制数来表示。

ASCII编码也有局限性,因为它只考虑了英文字母和数字以及一些常用符号,每个国家的语言文字不同,ASCII码的覆盖的字符量远远不够,所以后来又出现了ISO-8859系列、GB系列(GB2312GBKGB18030GB13000)、Big5EUC-KRJIS 等编码标准,这些都是各个国家为了支持本国语言而扩展出来的编码表,但为了能够在计算机系统通用,这些扩展均直接或间接兼容了ASCII码。

Unicode标准

虽然针对不同的语言开发出了不同的编码表,但是如果多语言混用还是会出现问题,例如想要中文日文混合输入,那么在GB中文系列的编码系统中,日文字符由于没有包含在内,会产生乱码(无法正确显示),而如果切换到日文编码系统JIS中,中文字符又会产生乱码。为了能在一个编码系统内覆盖所有国家的语言,Unicode便应运而生。Unicode除了归纳整理字符集以外,还根据基础的现代编码模型架构扩展出了自己的编码模型,自此字符编码算是终于发展到了一个稳定统一的阶段。而我们常见的UTF-8UTF-16UTF-32都是Unicode的编码方案,属于编码模型中的CEF层。

Unicode,全称为Unicode标准(The Unicode Standard),其官方机构Unicode联盟所用的中文名称为统一码,又译作万国码统一字元码统一字符编码,是信息技术领域的业界标准,其整理、编码了世界上大部分的文字系统使得电脑能以通用划一的字符集来处理和显示文字,不但减轻在不同编码系统间切换和转换的困扰,更提供了一种跨平台的乱码问题解决方案。Unicode由非营利机构Unicode联盟(Unicode Consortium)负责维护,该机构致力让Unicode标准取代既有的字符编码方案,因为既有方案编码空间有限,亦不适用于多语环境。

———《维基百科:Unicode》

字符编码模型

编码模型就是通过编码方案将人类可读的数据(字符)转换为机器存储数据(二进制数据0、1)。目前存在两种编码模型:传统编码模型和现代编码模型。

传统模型

又叫做简单字符集。在这种模型中,基本上就是直接将字符集里的字符用十进制的数字逐一编号,然后把十进制编号直接转为二进制码进行存储,可以说是直接定义了字符、码点(十进制编号)和存储(二进制流)的关系。

抽象字符编号(码点)二进制值
A10000 0001
B20000 0010
C30000 0011

早期的字符集实际上都是传统模型,与下面将要提到的编码字符集( CCS )不同,此时的术语字符集的含义实际上是包含了从抽象字符到最后的二进制流的映射。早期的ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集等都是简单字符集,而Unicode字符集不属于简单字符集。

简单字符集 按照惯例,人们认为字符集和字符编码是同义词,因为使用同样的标准来定义提供什么字符并且这些字符如何编码到一系列的代码单元(通常一个字符一个单元)。由于历史的原因,MIME和使用这种编码的系统使用术语字符集来表示用于将一组字符编码成一系列八位字节数据的整个系统。

——— 《维基百科:字符编码》

针对传统模型,简单介绍一下常见的几种字符集。

ASCII

  • 包含的字符与码点映射: 总共包含128个字符,其中前32个字符(码点 0 - 31)是不可见的控制字符,后95个字符(码点 32 - 126)是可见字符(包括编号33的空白符),最后一位(码点127)是DELETE命令(键盘上的 DEL 键)。
  • 映射关系: 码点直接转换为二进制进行存储:ASCII中的字符只用了一个字节(8位,最多可以表示256个字符)的低7位进行存储,最高位永远是0。
Untitled 3.png

GB系列

GB为 “国标” 的汉语拼音首字母缩写,主要是用于解决中文编码问题的。

我们国家有关部门按照ISO规范设计了GB2312双字节编码,但是GB2312是一个封闭字符集,只收录了常用字符总共也就7000多个字符,因此为了扩充更多的字符包括一些生僻字,才有了之后的GBK、GB18030、GB13000(“GB” 为 “国标” 的汉语拼音首字母缩写)。

按照 GB 系列编码方案,在一段文本中,如果一个字节是 0~127,那么这个字节的含义与 ASCII 编码相同,否则,这个字节和下一个字节共同组成汉字(或是 GB 编码定义的其他字符),所以GB系列都是兼容ASCII编码的。

https://p3-juejin.byteimg.com/tos-cn-i->k3u1fbpfcp/35f456798688453fbe2b0da464eef59e~tplv-k3u1fbpfcp-zoom-1.image

GB2312

  • GB2312是使用两个字节来表示汉字的编码标准,为了兼容ASCII,采用双字节变长编码方案

  • 总共包含6763个简体汉字和682个非汉字图形字符,覆盖的字符种类包括汉字、数字、罗马希腊字母,日文假名等。

  • 该标准规定:

    • 单字节码点在0~127范围时,字节表示的字符与ASCII一致
    • 连续2个字节的码点均大于127时,共同组成汉字字符,其中高字节(高低顺序从左到右)范围是0xA1 ~ 0xF71010 00011111 0111),低字节范围是0xA10xFE1010 00011111 1110

GBK

  • 是对GB2312的扩展,同样是双字节变长编码方案,共收录2w+的汉字字符(包含简体和繁体)和图形符号。GBK兼容GB2312,对原有的GB2312编码范围内的字符不作变更。

  • 因为GB2312要求双字节的最高位都要大于1(大于127),编码空间有限,上限不超过1万个字符,不足以支持中文体系下的庞大字符量,所以GBK扩展了GB2312的低字节范围,规定:

    • 单字节码点在0~127范围时,字节表示的字符与ASCII一致
    • 单字节码点大于127,就表示这是一个汉字字符的开始,和下一个字节共同组成汉字。

GB18030

  • 实际上GB18030是对GBK的扩展,但这种扩展和GBK多对GB2312 的扩展不同,并不是单纯利用没有使用的编码空间来扩充字符集数量,而是采用字节变长编码方案,最大支持扩展到4个字节,使得单字节区兼容ASCII字符集、双字节区兼容GBK字符集、四字节区对齐所有Unicode 字符集以及它们对应的码位。这也是为了保证GB系列编码到Unicode 的平稳过渡。

实现原理上主要是采用第二字节未使用到的0x30~0x39编码空间来判断是否四字节。

Untitled 5.png
  • 单字节,其值从0到0x7F。
  • 双字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x40到0xFE(不包括0x7F)。
  • 四字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x30到0x39,第三个字节的值从0x81到0xFE,第四个字节的值从0x30到0x39。

现代编码模型

现代编码模型相较于传统编码模型,将字符、码点再到二进制的映射做了分层处理。关于为什么会产生现代编码模型,最主要的目的还是为了更明确定义字符集的概念,把涉及到文本传输的流程清晰化,保证互联网的应用交互和可操作性。

首先是在[RFC 2130]上提出了三层模型(IAB模型)架构概念,后面,才有了后面的Unicode编码模型。

IAB三层模型

IAB三层模型中三层分别是 CCSCESTES

编码字符集 CCS(Coded Character Set)

抽象字符到一组非负整数(码点 code point)集合的映射,就是将抽象字符转换为数字形式。

在这一层,明确定义了字符集的涵盖内容,确定了当前字符集所包含的抽象字符范围,以及抽象字符到十进制编号(码点)的映射。

例如明确定义了当前字符集中只包含了A、B、C三个字符,三个字符分别进行数字编号1、2、3。

抽象字符编号(码点)
A1
B2
C3

字符编码方案 CES (Character Encoding Scheme)

是从代码单元序列到字节序列的映射。就是从一个编码字符集到一组八位二进制的映射。这个步骤决定字符的存储方式,包括二进制映射以及字节序

二进制映射

主要是指将码点用几个字节存储,这个数值关系怎么进行转换,例如上面的字符A,要求以占用2个字节的宽度,映射关系为数值一一对应的方式映射。那么字符A最终对应的值为0000 0000 0000 0001

字节序

主要是指当前映射的字节该以什么样的顺序存储。如果所有的字符只需要占用一个字节的宽度,那当然不涉及到字节序的问题。但是如果向上面那个例子,需要占用2个甚至多个字节,就需要考虑字节顺序的问题,其实就是字节的存放是从右往左还是从左往右的问题。

这个问题的产生主要涉及跟操作系统和底层硬件有关。由于历史原因,多字节数据单元在存储(寄存器、内存、磁盘等)方案上,不同软硬件厂商存在不同的实现方式,大体分为大端(big-endian)小端(little-endian) 两种方案。这个没有孰轻孰重之分,主要是由于在设计之初的认知习惯差异不同导致。比如WindowsFreeBSDLinux 是小端序,Mac是大端序。

为了方便说明,我们这里举个例子,比如存一个整数值「305419896」对应16进制是0x12345678,有人习惯从左到右按顺序去存,也有人说高位当然要放到高位地址而低位放到低位地址,要从右往左存。于是就有了下面两种存取方式。

Untitled 6.png
  • 小端序( Little-Endian)就是低位字节(即小端字节、尾端字节)存放在内存的低地址,而高位字节(即大端字节、头端字节)存放在内存的高地址
  • 大端序(Big-Endian )就是高位字节(即大端字节、头端字节)存放在内存的低地址低位字节(即小端字节、尾端字节)存放在内存的高地址

传输编码语法 TES (Transfer Encoding Syntax)

主要用于将通过CCSCES进行转换后的二进制序列值转换为可以被特定协议传输的格式。常见的TES有 base64gzip等。

Unicode五层模型

IAB三层模型更多的是确定了现代编码模型的层次架构,而Unicode五层模型则可以说是对这个模型的真正实现。我们现在常说的现代编码模型,基本上是来自于Unicode五层模型的定义,只不过在多数情况下,会忽略介绍TES 层,因为认为这一层与传统认知上的字符编码关系不大。

由统一码和通用字符集所构成的现代字符编码模型,将字符编码的概念分为:有哪些字符、它们的编号、这些编号如何编码成一系列的“码元”(有限大小的数字)以及最后这些单元如何组成八位字节流。区分这些概念的核心思想是创建一个能够用不同方法来编码的一个通用字符集。为了正确地表示这个模型需要更多比“字符集”和“字符编码”更为精确的术语表示。

—— 《维基百科》

Unicode五层模型中,主要把IAB中的CCSCES进行了更细致的拆分:在IAB中的CCS,关于字符集应该包含哪些字符被单独拆分成了ACR层,CCS的职责更清晰,专注于处理字符和码点的映射;而对于IAB中的CES层,则将码点和二进制的转换放到了CEF层,CES只负责字节序的处理。

抽象字符库 ACR (Abstract Character Repertoire)

抽象字符库 ACR是一个系统支持的所有抽象字符的集合。抽象字符库分为固定和开放两种:

  • 固定
    • 固定的字符库代表着当前的字符集合一定被确定,就不再会修改,也不允许添加新的字符进去。
    • 在大多数字符编码中,库都是固定的(一旦确定就永远不会改变)且通常很小。向给定字符库添加新字符通常是创建一个新库(新库会有自己的目录号)构成一个新对象。
  • 开放
    • 开放字符库就是在已经对现有字符编码的基础上,如果有新的字符需要加入编码,也是可以添加进来的,不会生成新的对象。

编码字符集 CCS(Coded Character Set)

是将字符库 ACR 中每个字符映射到1个坐标(整数值对:x, y)或者映射为1个非负整数。字符集及码位映射称为编码字符集。

字符编码形式 CEF (Character Encoding Form)

是从 CCS 中使用的整数集到代码单元(码元)序列集的映射。可以理解为定义了整数的码点将会转换为多少位数的二进制值以及如何映射。而这个多少位,就由码元的单位量和数量来决定。

  • 码元是一个单位量,定义了一个单位下的二进制宽度。例如UTF-8中,单位码元为8位,而UTF-16中,单位码元为16位。

  • 编码形式分为变长编码方式(可变宽度)定长编码方式(固定宽度)

    • 例如UTF-8 中不同的字符可能需要 1 ~ 4 个码元来表示,这种编码方式称为变长编码方式(相反,如果所有字符都使用固定数量的码元表示,则称为定长编码方式,如 UTF-32)。

字符编码方案 CES (Character Encoding Scheme)

也称作 “序列化格式“ ( Serialization Format ),指的是将字符编号进行编码之后的码元序列映射为字节序列(即字节流)的形式,以便经过编码后的字符能在计算机中进行处理、存储和传输。

传输编码语法 TES (Transfer Encoding Syntax)

定义同上。

Unicode

Unicode与简单字符集不同,它是按现代编码模型进行设计的一套字符编码体系,涵盖抽象字符集、编号、逻辑编码、编码实现。具体的层次结构已经在上面有所解释,接下来主要解析一下UnicodeCCSCEF层,因为这2层是最靠近我们认知中的字符编码流程与实际应用。

Unicode字符集(CCS)

Unicode字符集大小总共为22121617=216(24+1)=220+2162^{21}(2^{16} * 17 = 2^{16} * (2^4+1) = 2^{20}+2^{16})Unicode字符集的存储空间至少需要3个字节(24位)。

Unicode字符集中,码点表示为U+xxxx(十六进制)的形式,例如U+0001

平面空间

Unicode的出现,主要就是为了解决各个国家的字符标准不兼容的问题,所以为了包含容纳全部的字符,Unicode字符集的体积就特别的大,为了便于管理以及后期的优化,Unicode字符集根据字符的使用频率和重要程度对字符进行编排处理,将字符编排为17组,每组称为平面(Plane),而每个平面拥有65536(即2162^{16})个码点,这就是Unicode平面空间,也叫做Unicode字符平面映射

基本多语言平面

其中,常用的字符被放置在基本多语言平面(Basic Multilingual Plane, BMP)也叫做基本平面0号平面(Plane 0)中,编号从U+0000U+FFFF

而且规定,基本平面中的U+D800 U+DFFF这个区间范围永久保留,要求不映射任何字符。后来UTF-16利用这个区间的规定,扩展了字符编码方案。

辅助平面

剩余的16个平面可以统称为辅助平面,用于存放那些不常用的或者后续可能会新增的字符。

Untitled 7.png

编码方案(CEF)

已知Unicode字符集以及对应的码点映射,那么如何将码点转换为二进制,就需要Unicode编码模型中的CEF层来实现。其中Unicode转换格式(Unicode Transformation Format,简称为UTF,Unicode字符集转换格式)就是实现方式的一种,除了UTF系列之外,还有UCS-2/4GB18030等。常见的UTF-N中的N表示的是码元单位量。

UTF-8

最早的Unicode编码是多字节定长编码方案,但实际在使用过程中,较小值的码点字符(一般是ASCII字符)使用频率较高,如果直接采用多字节编码,会导致大量浪费内存空间。所以设计出了UTF-8的编码方案,向后兼容ASCII

Unicode中前128个字符,使用与ASCII码相同的二进制值的单个字节进行编码,而且字面与ASCII码的字面一一对应,这使得原来处理ASCII字符的软件无须或只须做少部分修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或发送文字优先采用的编码方式。

—— 《维基百科:UTF-8》

编码规则

  • UTF-8是一种变长编码方案。码元单位宽度位8位(一个字节),使用用1-4个码元来进行编码。
  • 主要分为前缀码位(固定位)和码点有效位。其中,码点表示位从低位开始填充,填充不完,剩下的位置补0。
Untitled 8.png
例如“汉”的Unicode码点是U+6c49
1、确定字节数和格式:
0x6c49: 110 1100 0100 1001
当前码点位数在16位之内,所以使用3个字节(24位)
格式为 1110xxxx 10xxxxxx 10xxxxxx

2、填充
将码点的二进制数从最低位开始,依次往前填充,没有填满的位置补0:
1110110 10110001 10001001
转换成十六进制就是 0xE6 0xB7 0x89

解码判断

根据前缀码来区分当前字符是由几个字节组成。

> 如果首字节以 0 开头,则是**单字节编码**(即单个单字节码元); 
> 
> 如果首字节以 110 开头,则是**双字节编码**(即由两个单字节码元所组成的双码元序列);
> 
> 如果首字节以 1110 开头,则是**三字节编码**(即由三个单字节码元所组成的三码元序列),以此类推。

UTF-16

Windows 内核、Java、Objective-C (Foundation)、JavaScript 中都会将字符的基本单元定为两个字节的数据类型,也就是我们在 C / C++ 中遇到的 wchar_t 类型或 Java 中的 char 类型等等,这些类型占内存两个字节,因为 Unicode 中常用的字符都处于 0x0 - 0xFFFF 的范围之内,因此两个字节几乎可以覆盖大部分的常用字符。

编码规则

  • UTF-16是一个变长编码方案。码元单位宽度为16位,在这种编码方案中需要1~2个码元来对Unicode字符集进行编码。

  • UTF-16中,针对不同平面的字符,采取不同的编码策略:

    • 基本平面

      • 对于该平面的字符(总共包括2162^{16}个码点),使用1个码元(2个字节)来进行编码存储。

      • 该平面码点的映射规则是数值与二进制值一一对应映射。

        码点二进制值
        U+00110000 0000 0001 0001
    • 辅助平面

      • 辅助平面包含2102^{10}个码点,至少需要3个字节进行编码存储,所以在UTF-16中,使用2个码元(4个字节)来存储辅助平面的字符。

      • 这些平面字符的编码则是通过代理对来进行编码

        • 首先码点减去 0x10000得到一个20位的二进制数,然后按10位划分为2部分,每部分10位,不足部分补0。按字节序从左到右的顺序分为高位和低位:

          • 高10位加上0xD800得到第一个码元或称作前导代理(lead surrogates)或者高位代理(high surrogate),最终第一个码元的范围为U+D800U+DBFF

          • 低10位加上 0xDC00得到第二个码元或称作后尾代理(trail surrogates)或低位代理(low surrogate),最终第二个码元的范围为 U+DC00U+DFFF

      U+10437编码(𐐷)为例:
      1、得到20位二进制值:
      0x10437 - 0x10000 = 0x00437
      
      0x10437: 0001 0000 0100 0011 0111
      0x10000: 0001 0000 0000 0000 0000
      0x00437: 0000 0000 0100 0011 0111
      
      2、分段:
      0000000001 0000110111
      
      3、相加:
      0xD800: 1101 1000 0000 0000
      0xDC00: 1101 1100 0000 0000
      前10位加上0xD800得到第一个码元:1101 1000 0000 0001
      后10位加上0xDC00得到第二个码元:1101 1100 0011 0111
      (实际上从这里可以看出,对位的相加结果实际上就是填充的过程。)
      
      4、结果:
      最后的得到的4字节结果是:
      1101 1000 0000 0001 1101 1100 0011 0111
      转换为16进制可得该字符的UTF-16编码为 0xD801 0xDC37
      
      
Untitled 9.png

解码判断

  • 判断当前字符是2个字节组成还是4个字节组成,就是利用了基本平面的U+D800 - U+DFFF这个区间来进行判断。
  • 当我们遇到两个字节,发现它的码点在U+D800U+DBFF 之间,就可以断定,紧跟在后面的两个字节的码点,应该在 U+DC00U+DFFF 之间,这四个字节必须放在一起解读。

UTF-32

编码规则

  • UTF-32是定长编码方案。码元单位宽度位4个字节(32位)。

  • 它的编码规则就是码点与二进制值一一对应的规则。

    U+0000 = 0x0000 0000
    U+597D = 0x0000 597D
    

UTF-32 的优点在于,转换规则简单直观,查找效率高。缺点在于浪费空间,同样内容的英语文本,它会比 ASCII 编码大四倍。这个缺点很致命,导致实际上没有人使用这种编码方法,HTML 5 标准就明文规定,网页不得编码成 UTF-32。

结语

我在整理字符编码相关的时候翻阅了很多资料,尽管尽可能全的整理相关内容,但是字符编码发展历史已久,在Unicode标准之前还经历了其他的方案,包括微软/IBM为了尽可能多的支持字符集发展出了代码页(Codepage,又称内码表)以及ANSI编码,ISO组织推出的字符集标准ISO系列UCS(Universal Character Set),还有UnicodeISO 10646的关系,这些内容均未在本文中介绍。

同时本文旨在通过编码模型的角度去理解字符编码的流程,包括关于字符集介绍的相关内容也是进行了整理和删减。

如果对这些省略的部分感兴趣,可以自行搜索相关关键字进行了解。

文章中部分内容包含了自己的理解,如果有误,欢迎评论区指正。

参考文章