字符集、字符编码
百度百科:
字符(Character) 是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。
字符集(Character set) 是多个字符的集合,字符集的种类较多,每种字符集包含的字符数量及字符种类都不尽相同,常见的字符集:ASCII、GB2312、BIG5、GB18030、Unicode。
计算机要准确的处理各种字符集文字,需要进行 字符编码,以便计算机能够识别和存储各种文字。
知乎某回答:
字符集:为每一个「字符」分配一个唯一的 ID(学名为 码位/代码点/Code Point)。
字符编码:将「码位」转换为 字节序列 的规则(编码/解码 可以理解为 加密/解密 的过程)。
个人理解:
字符集:每个字符用一个唯一的 数字 来表示,这样的集合称为字符集(用数字来表示各种字符)。
字符编码:将字符存储在 计算机 内存/磁盘/网络 的一种编码方案(在计算机中的表示/存储方法)。
ASCII 字符集&编码
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语,ASCII 是现今最通用的 单字节编码系统。
ASCII字符集:控制字符(回车、制表等)、可显示字符(英文字母、阿拉伯数字、英文标点符号)。
ASCII码点:码点范围为 0~127,共 128 个字符。其中 0~31 和 127 为控制字符,32~126 为可显示字符。
ASCII编码:因为只有 128 个字符,所以用 1 个字节(8 个二进制位)来存储是最自然的。而 0~127 这 128 个数字,只需要使用最低的 7 个二进制位,最高位没有用到,因此 ASCII 编码规定,最高位为 0。
ASCII缺点:只编码了 26 个基本拉丁字母、阿拉伯数字及英式标点符号,因此只能用于显示现代英语。而且在处理英语当中的外来词时,如 naïve、café、élite,重音符号必须去掉,即使这样会违反拼写规则。
Unicode 字符集
Unicode 官方中文名称为统一码,是信息技术领域的业界标准。它整理、编码了世界上大部分的文字系统,使得电脑可以用更为简单的方式来呈现和处理文字。
Unicode 伴随着 通用字符集(Universal Character Set,UCS)的标准而发展,同时也以书本的形式对外发表。Unicode 至今仍在不断增修,每个新版本都加入更多新的字符。
目前最新版本为 2022 年 9 月公布的 15.0.0,已经收录超过 14 万个字符(第十万个字符于 2005 年采纳)。
Unicode 除了包含视觉上的字形、编码方法、标准的字符编码资料外,还包含了字符特性(如大小写字母)、书写方向、拆分标准等特性的资料库。
Unicode 的发展由非营利机构 统一码联盟 负责,该机构致力于让 Unicode 方案取代既有的字符编码方案。因为既有的方案往往空间非常有限,亦不适用于多语环境。
Unicode 字符集分为 17 个 平面(plane),平面编号为 0 到 16。每个平面有 2^16 个 码位(code point)空间。17 个平面的码位空间可表示为 U+xx0000
~ U+xxFFFF
,xx 为 平面 的十六进制值 0x00
~ 0x10
。
0 号平面称为 基本多文种平面(Basic Multilingual Plane,BMP),大部分常用字符都位于 BMP。
UTF-32 字符编码
UTF-32 是一种 固定长度 的字符编码,用于编码 Unicode 代码点,每个代码点恰好使用 32 位(4 个字节),但由于 Unicode 代码点数量远少于 2^32 个,所以实际上只需要 21 位,其余高位规定为 0。UTF-32 中的每个 32 位值代表一个 Unicode 代码点,并且完全等于该代码点的数值。
UTF-32 的主要优点是在一系列代码点中查找第 N 个代码点是恒定时间操作(可想象成一个 单位长度为 4 字节的数组)。相比之下,可变长度 的编码格式需要线性的时间来从字符串的开头计算第 N 个代码点。
UTF-32 的主要缺点是空间效率低,每个代码点使用 4 个字节,包括始终为零的高 11 位。在大多数文本中,超出 BMP 的字符相对较少(表情符号除外),并且通常可以在估计大小时忽略。这使得 UTF-32 的大小接近 UTF-16 的两倍。甚至可以是 UTF-8 大小的四倍,具体取决于 ASCII 子集中的字符数。
UTF-16 字符编码
UTF-16 是一种 可变长度 的字符编码,用于编码 Unicode 代码点,每个代码点使用一个或两个 16 位的 代码单元(code unit) 编码。UTF-16 起源于早期过时的固定长度为 16 位的 UCS-2 编码。
对于 BMP 字符,UTF-16 使用一个 code unit 表示,其值等于对应 code point 的值。对于其它平面的字符,UTF-16 使用两个 code unit 表示(称之为 代理对),前一个 unit 为 前导代理,后一个 unit 为 后尾代理。
UTF-16 被作为 Windows API、Java、JavaScript、ECMAScript 等系统的内部编码。有时也用于 Windows 上的纯文本和文字处理的数据文件。但很少用于类 Unix 系统上的文件(它们大多使用 UTF-8)。自 2019 年 5 月起,微软开始支持 UTF-8 并鼓励使用它。
与 UTF-32 相比,UTF-16 的空间效率更高,因为大部分常用字符(BMP)使用一个 code unit 表示,因此可近似看作是 2 字节长的固定长度编码。并且由于 UTF-16 的 code unit 编码特点,给定任意一个 unit 值,都可以知道它是 BMP unit 还是 前导代理 还是 后尾代理,因此在程序中处理起来也比较容易。
UTF-8 字符编码
从上述内容可以知道,无论是 UTF-16/32 还是 UCS-2/4 ,一个字符都需要多个字节来编码,这对那些只需要 单字节编码 的国家来说,很浪费存储和带宽,尤其是在那个存储和带宽都很匮乏的年代。
因此,UTF-8 产生了。在 UTF-8 编码中,ASCII 字符集中的字符还是其 ASCII 码的值,只需要 1 个字节表示,其余的字符需要 2、3、4 字节表示。因此和 UTF-16 一样,是 可变长度 的字符编码。
UTF-8 的编码规则:
对于 ASCII 字符,使用 单字节编码,其编码值与 ASCII 值相同。其中 ASCII 值的范围为 0~0x7F,编码的二进制值的最高位为 0(这个正好可以用来区分单字节编码和多字节编码);
对于 其它字符,使用 多字节编码,假设使用 N 个字节,则:首个字节的高 N 位都为 1,第 N+1 位为 0;其余字节的高 2 位为 10;这些字节的其余位用来存储 Unicode 中的码位值;如下表:
字节数 | Unicode 码点值 | UTF-8 编码值 |
---|---|---|
1 | 000000 - 00007F | 0xxxxxxx |
2 | 000080 - 0007FF | 110xxxxx 10xxxxxx |
3 | 000800 - 00FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
4 | 010000 - 10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
自 2009 年以来,UTF-8 一直是万维网的最主要的字符编码方式。截止到 2019 年 11 月,在所有网页中,UTF-8 编码应用率高达 94.3%(其中一些仅是 ASCII 编码,因为它是 UTF-8 的子集),而在排名最高的 1000 个网页中占 96%。
互联网邮件联盟(IMC)建议所有电子邮件程序都能够使用 UTF-8 展示和创建邮件。W3C 建议 UTF-8 作为 XML 文件和 HTML 文件的默认编码方式。互联网工程工作小组(IETF)要求所有互联网协议都必须支持 UTF-8 编码。在绝大多数现代 Linux 中,默认字符编码为 UTF-8。
乱码的本质
乱码的本质:在编码(写入)和解码(读取)时,使用了不兼容的两种字符编码。
好比数据加密,加密和解密时用的算法不同或秘钥不同,结果必定不符合预期。
总结
1、ASCII 即代表字符集,也代表字符编码,是最流行的 单字节 字符集&字符编码。
2、Unicode 是字符集,UTF-8、UTF-16、UTF-32 是针对 Unicode 字符集的编码方式。
UTF-8、UTF-16、UTF-32、UCS-2、UCS-4 对比:
编码方案 | UTF-8 | UTF-16 | UTF-32 | UCS-2 | UCS-4 |
---|---|---|---|---|---|
编码空间 | 0 - 10FFFF | 0 - 10FFFF | 0 - 10FFFF | 0 - FFFF | 0 - 7FFFFFFF |
最少字节数 | 1 | 2 | 4 | 2 | 4 |
最多字节数 | 4 | 4 | 4 | 2 | 4 |
依赖字节序 | 否 | 是 | 是 | 是 | 是 |
字节顺序标记(byte-order mark,BOM):用来标识 UTF/UCS 编码的文本的字节序是大端还是小端。
UTF-8 不需要借助 BOM 来区分字节序,不建议在 UTF-8 文本中使用 BOM 标记,特别是类 Unix 环境下。