浅谈计算机字符编码

作者: 潘峰 / 2019-10-28 / 分类: Work

字符编码

浅谈计算机字符编码

程序员如果不弄懂字符编码它就会像幽灵一般纠缠你整个职业生涯,各种灵异事件会接踵而来,挥之不去。
— 刘志军 [知乎]

基础知识:
1 bit = 1 位  = 2 种两种可能性(0或1)
1 byte = 1 字节 = 1 个英文字符 = 8 bit = 2 ^ 8 次方 = 256 种可能性

一、字符编码简介

计算机字符编码是一种将字符映射为计算机内部表示的规则或方案。

在计算机中,所有的数据在存储和运算时都要使用二进制数表示(因为计算机用高电平和低电平分别表示 1 和 0),而具体用哪些二进制数字表示哪个符号,就需要一种合理的机制来实现,这种机制就是计算机字符编码规则。

ASCII

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)
是诞生最早的一种单字节的编码方案,它指定用 7 位(后扩展为 8 位)二进制数组合来表示 128 或 256 种可能的字符,
主要用于显示现代英语,也包括了基本的拉丁字母、数字、标点符号。

MBCS

MBCS(Muilti-Bytes Charecter Set,多字节字符集)
使用变长字节序列来表示字符,支持多种语言和字符集。
在 MBCS 中,每个字符可以由一个或多个字节表示,具体使用多少字节取决于所使用的字符和字符集。
需要注意的是,MBCS 并不是一个单一的字符编码规则,而是一个通用的术语,可以用于描述一类使用变长字节序列表示字符的编码方案。

ANSI

ANSI(American National Standards Institute)
ANSI 编码并非一个标准化的字符编码,它的具体含义和范围在不同的上下文中可能有所差异。
在计算机领域中,ANSI 编码通常用于指代 Windows 系统中的字符编码方案。
在简体中文系统下,ANSI 编码代表 GB 2312 编码;日文操作系统下,ANSI 编码代表 Shift_JIS 编码;韩文操作系统下,ANSI 编码代表 Euc-kr 编码。
不统一的编码标准会不可避免地出现冲突。

GBK 和 GB 2312

见上

UCS

Universal Character Set, UCS(中文:通用字符集)是由 ISO 制定的 ISO 10646(或称 ISO/IEC 10646)标准所定义的标准字符集。

  • UCS-2:使用两个定长的字节来表示一个字符
  • UCS-4:是一个更大的尚未填充完全的 31 位字符集,加上恒为 0 的首位,共需占据 32 位,即四字节

Unicode

Unicode(中文:万国码、国际码、统一码、单一码)
是一个标准化的字符编码系统,用于表示世界上几乎所有的字符,包括各种语言的字母、符号、标点符号、数学符号、表情符号等。

Unicode 的目标是为不同的语言和字符提供一个统一的编码标准,使得各种字符可以在计算机系统中进行一致的表示和处理。
它使用唯一的代码点来表示每个字符,范围从 U+0000 到 U+10FFFF。并提供了包括文本文件、数据库存储、通信协议等各个领域的字符编码方案。

Unicode 伴随着 UCS 的标准而发展,至今仍在不断增修,每个新版本都加入更多新的字符。
由于计算机的内存比较大,并且字符串在内容中表示时也不会特别大,所以在计算机内存中使用 Unicode 来处理字符。

Unicode 编码空间共有 17 个平面,每个平面包含一定范围的代码点,其中常见的平面有:

  • 基本多语言平面(BMP,Basic Multilingual Plane):
    范围从 U+0000 到 U+FFFF,包含了大部分常见的字符,包括拉丁字母、数字、标点符号、符号、汉字等。
  • 补充平面(Supplementary Planes):
    范围从 U+10000 到 U+1FFFFF,包含了辅助字符集、专用区域补充、补充符号等。

UTF-8

UTF-8(8-bit Unicode Transformation Format)是一种变长的字符编码方案,用于在计算机系统中表示 Unicode 字符。
UTF-8 使用一至四个字节为每个字符编码,可以用来表示 Unicode 标准中的任何字符,具体使用字节数量可根据字符的 Unicode 编码范围来决定。
UTF-8 可以向后兼容 ASCII 编码,避免了直接使用 Unicode 编码传输效率低下,大量浪费存储空间的问题。

UTF-8 的特点是对不同范围的字符使用不同长度的编码。

  • 对于 0x00-0x7F 之间的单子节字符,UTF-8 编码与 ASCII 编码完全相同。
  • 对于多字节的字符,第一个字节的高位标识了字节数,后续的字节使用特定的前缀来表示。这些前缀位于 0x80 到 0xBF 之间。
  • UTF-8 使用了不同的编码方案来表示不同范围的 Unicode 字符,例如使用 2 个字节表示 U+0080 到 U+07FF 的字符,使用 3 个字节表示 U+0800 到 U+FFFF 的字符,使用 4 个字节表示 U+10000 到 U+10FFFF 的字符。

UTF-16 和 UTF-32

Unicode 和 UTF-8 的区别

UTF,是为 Unicode 字符集设计的一种在存储和传输时节省空间的实现方式。
简单来说:Unicode 是「字符集」,UTF-8 是「编码规则」。
从通信角度的理论来说:unicode 是信源编码,对字符集数字化;UTF-8 是信道编码,为更好的存储和传输。

Unicode 编码(十六进制) UTF-8 字节流(二进制)
00000000 - 0000007F 0xxxxxxx
00000080 - 000007FF 110xxxxx 10xxxxxx
00000800 - 0000FFFF 1110xxxx 10xxxxxx 10xxxxxx
00010000 - 001FFFFF 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx
00200000 - 03FFFFFF 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
04000000 - 7FFFFFFF 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

二、Python 中字符编码问题

在 Python 中,解释器会在解释执行代码前,先将代码通过系统默认编码方式读入系统内存,再由编译器以特定编码格式编码交付虚拟机解释执行。
即在 Python 2.x 中,解释器默认会将代码以 ASCII 编码方式读入系统内存,但编译器却不会在内存中将代码自动转换为 Unicode;
而在 Python 3.x 中,解释器默认会将代码以 UTF-8 编码方式读入系统内存,并且编译器会在内存中将代码自动转换为 Unicode。

Python 查看系统默认编码格式问题

在 Python2.x 的版本中,系统默认编码格式为 ascii,我们可以通过以下代码查看 Python 的系统默认编码:

>>> import sys
>>> sys.getdefaultencoding()
'ascii'

Python2.x 文件头部设置编码格式

当我们在 Python2.x 文件的开头加上 # -*- coding: gbk -*-# encoding=utf-8 时,会告诉 Python 解释器读取该文件时的编码方式是 utf-8,这时,Python 解释器便会将代码通过 UTF-8 的方式读入系统内存,同时编译器也只会把代码以 UTF-8 的编码格式交付虚拟机解释执行。

Python2.7 编码处理

  • 将 unicode 输出成中文:
    >>> unic ='\u4f60\u597d'
    >>> print(unic.decode('unicode-escape'))
    你好
    

Python3.x 编码处理

  • 将 unicode 输出成中文:
    >>> unic
    

图解

graph TB
Unicode --> |encode| GBK
Unicode --> |encode| UTF-8
GBK --> |decode| Unicode
UTF-8 --> |decode| Unicode
sequenceDiagram
Unicode码->>字符:decode(unicode-escape)
字符->>Unicode码:encode(unicode-escape)

参考来源 > https://zh.wikipedia.org/wiki/Unicode > https://foofish.net/unicode_utf-8.html > https://www.zhihu.com/question/31833164/answer/381137073