Unicode 字符编码模型_字符编码模式(CEF)

转载须注明出处:简书@Orca_J35
本文参考资料的列表位于 Unicode 字符编码模型_简介

为了便于理解,需先了解如下术语:

  • Unicode 标量值 (Scalar Value):除开高代理码点(high-surrogate)和低代理码点(low-surrogat )之外的任何 Unicode 码点都是标量值,具体范围是 0x0 ~ 0xD7FF 和 0xE000 ~ 0x10FFFF。代理码点不能通过"编码模式"映射为"编码单元序列",只有标量值可被映射为"编码单元序列"。(See definition D76 in Section 3.9, Unicode Encoding Forms.)

  • 编码单元(code unit):也称编码值(Code Value),表示用于处理或交换编码文本的基本单元。Unicode 标准在 UTF-8 编码模式中使用 8-bit 编码单元;在 UTF-16 编码模式中使用 16-bit 编码单元;在 UTF-32 编码模式中使用 32-bit 编码单元。

Unicode 字符编码模式是指从"标量值"到"编码单元序列"的可逆映射,用于为每个标量值分别分配一个唯一的"编码单元序列"。根据"编码单元序列"的长度是否可变,可将Unicode 字符编码模式分为两类:

  • 固定宽度 (fixed width) 编码模式:仅使用一个编码单元,但编码单元的位数不同。

    Type Each character encoded as Notes
    16-bit (UCS-2) a single 16-bit quantity within a code space of 0..FFFF
    32-bit (UCS-4) a single 32-bit quantity within a code space 0..7FFFFFFF
    32-bit (UTF-32) a single 32-bit quantity within a code space of 0..10FFFF
  • 可变宽度 (variable width) 编码模式:"编码单元序列"的长度可变。如下:

    Name Characters are encoded as Notes
    UTF-8 a mix of one to four 8-bit code units in Unicode and one to six code units in 10646 used only with Unicode/10646
    UTF-16 a mix of one to two 16 bit code units used only with Unicode/10646

1. 为什么需要 CEF

既然已经有了已编码字符集,那么通过获取"已编码字符"的码点值,计算机不就可以识别目标字符了么?为什么还需要"字符编码模式"喃?因为还存在如下问题:

  1. 假设以固定长度存储码点,那么每个字符至少需要占用 3 个字节。对于码点值小于 0x0000FF 字符(如英文字母),仅有最后一个字节携带有效信息,其余字节全是 0,会浪费存储空间。
  2. 如果以可变长度存储每个码点,则可能无法区分不同的标量值:字母 'A' 和 'B' 的码点值是 0x41 和 0x42,汉字 '䅂' 的码点值是 0x4142,那么当出现数值 0x4142 时,到底是表示 'A' 和 'B',还是表示 '䅂' 喃?由于二进制数据中并没有明确的"边界信息",所有并不能对二者做出区分。
  3. 通常计算机系统会以一个固定的 bit 长度来表示数值。假设某个系统以 8-bit 的无符号整数来存储字符信息,那么当标量值大于 0xFF 时,又该如何存储数据喃?

为了解决上述问题,便需要通过"字符编码模式"在"码点值"与"编码单元序列"间建立起映射的关系,使得每个码点仅有唯一一个对应的"编码单元"序列(解决第 2 个问题)。如果采用可变长度的"编码模式",还可减少空间的浪费(解决第 1 个问题)。比如在 UTF-8 编码模式下:

  • 字母 'A' 被映射为一个编码单元 0x41
  • 字母 'B' 被映射为一个编码单元 0x42
  • 汉字 '䅂' 被映射为三个代码单元,分别是 0xE4、0x85、0x82。标量值通过 UTF-8 映射为"编码单元序列"后,拥有明确的边界信息,不会与其他编码单元混淆(解决第 2 个问题)。

可以看到汉字 '䅂' 被映射为三个代码单元,每个代码单元是 8-bit,这说明我们可以在 8-bit 的系统中使用"编码单元序列"来表示标量值大于 0xFF 字符数据(解决第 3 个问题),可变宽度 编码模式正是基于这样的思路产生的。在可变宽度编码模式中,我们可以用代码单元(8-bit 或 16-bit)构成的序列来表示任意标量值。

2. UTF

UTF (Unicode transformation format ) 是将每个标量值分别映射到一个唯一字节序列的算法,属于"Unicode 字符编码模式"的具体实现方式。UTF 包含三中模式:UTF-8、UTF-16、UTF-32,且每种 UTF 算法都是可逆算法。

2.1 UTF-8 CEF

UTF-8 编码模式 (Encoding Form):一种 Unicode 编码模式,会为每个标量值分别分配一个唯一的无符号字节序列,该序列的长度是 1 ~ 4 字节(可变宽度)。另外,UTF-8 与 ASCII 兼容。 (See definition D92 in Section 3.9, Unicode Encoding Forms.)

下表展示了 UTF-8 中比特位编码方式:

标量值(2进制) 标量值(16进制) First Byte Second Byte Third Byte Fourth Byte
00000000 0xxxxxxx 0x0000..0x007F 0xxxxxxx
00000yyy yyxxxxxx 0x0080..0x07FF 110yyyyy 10xxxxxx
zzzzyyyy yyxxxxxx 0x0800..0xFFFF 1110zzzz 10yyyyyy 10xxxxxx
000uuuuu zzzzyyyy yyxxxxxx 0x10000..0x10FFFF 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx

编码后的字节序列和标量值间的对应关系:

标量值 First Byte Byte Second Third Byte Fourth Byte
U+0000..U+007F 00..7F
U+0080..U+07FF C2..DF 80..BF
U+0800..U+0FFF E0 A0..BF 80..BF
U+1000..U+CFFF E1..EC 80..BF 80..BF
U+D000..U+D7FF ED 80..9F 80..BF
U+E000..U+FFFF EE..EF 80..BF 80..BF
U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
U+100000..U+10FFFF F4 80..8F 80..BF 80..BF

2.2 UTF-16 CEF

UTF-16 编码模式 (Encoding Form):一种 Unicode 编码模式,会为 U+0000..U+D7FF 和 U+E000..U+FFFF 中的每个标量值分别分配一个唯一的无符号 16-bit 编码单元(编码单元的值与 Unicode 标量值相等);会为 U+10000..U+10FFFF 中的每个标量值分别分配一个唯一代理对。下表展示了 UTF-16 中比特位编码方式: (See definition D91 in Section 3.9, Unicode Encoding Forms.)

Scalar Value UTF-16
xxxxxxx xxxxxxxxx xxxxxxxx xxxxxxxx
000uuuuu xxxxxxxx xxxxxxxx 110110wwwwxxxxxx 110111xxxxxxxxxx

2.2.1 代理对

surrogate pairs

代理对 (Surrogate Pair):用于表示辅助平面中的标量值,由包含两个 16-bit 编码单元的序列构成。代理对中的第一个值被称作高代理(high-surrogate)编码单元,第二个值被称作低代理(low--surrogate)编码单元。(See definition D75 in Section 3.8, Surrogates.)

将标量值映射为代理对的算法大致如下:

假设辅助平面中某个标量值的十六进制值是x,显然:
x ∈ (0x1_0000~0x10_FFFF)
首先,将x的减去0x1_0000,得到y:
∴ y = x-0x1_0000 ∈ (0x00000~0xF_FFFF)
将 y 表示为二进制,并将高10位记作h,低十位记作l,可得:
y = 0bhhhh_hhhh_hhll_llll_llll
将y的高10位与高代理项的基准值0xD800相加,便可得高代理项high:
high = (y // 0x400)+0xD800
将y的低10位与低代理项的基准值0xDC00相加,便可得低代理项low:
low = (y % 0x400)+0xDC00

代理对由 high 和 low 构成了,high 表示高代理编码单元,low 表示地代理编码单元。"高代理编码单元"的值位于 0xD800 ~ 0xDBFF 之间,"低代理编码单元"的值位于 0xDC00 ~ 0xDFFF 之间。为了避免与拥有相同值的码点混淆,所以在 U+D800 ~ U+DFFF 内的码点是不能通过"编码模式"映射为"编码单元序列"的,只有标量值可被映射为"编码单元序列"。这样的设计目的是为了便于判断某个"编码单元"是否是代码对中的一部分。

用 Python 描述计算过程如下,不考虑输入错误:

def get_surrogate_pairs(char_or_code):
    """char_or_code:单个字符或码点值"""
    if isinstance(char_or_code, str):
        code_point = ord(char_or_code)
    else:
        code_point = char_or_code
    code_point -= 0x10000
    high_surrogate = (code_point // 0x400)+0xD800
    low_surrogate = (code_point % 0x400)+0xDC00
    print(hex(high_surrogate), hex(low_surrogate))

get_surrogate_pairs("𐐷")
get_surrogate_pairs("𤭢")
get_surrogate_pairs(0x10FFFF) # 输出最大码点值的代理对

输出:

0xd801 0xdc37
0xd852 0xdf62
0xdbff 0xdfff

为了便于理解,再补充几个术语:

代理码点 (Surrogate Code Point):位于 U+D800 ~ U+DFFF 之间的 Unicode 码点属于作代理码点,保留共 UTF-16 使用。UTF-16 使用一对代理编码单元"表示"辅助码点。

高代理码点 (High-Surrogate Code Point):位于 U+D800 ~ U+DBFF 间的 Unicode 码点属于高代理码点。(See definition D71 in Section 3.8, Surrogates.)

高代理编码单元 (High-Surrogate Code Unit):位于 0xD800 ~ 0xDBFF 间的 16-bit 编码单元,在 UTF-16 中被用作代理对的第一个编码单元。(See definition D72 in Section 3.8, Surrogates.)

低代理码点 (Low-Surrogate Code Point):位于 U+DC00 ~ U+DFFF 间的 Unicode 码点属于低代理码点。(See definition D73 in Section 3.8, Surrogates.)

低代理编码单元 (Low-Surrogate Code Unit):位于 0xDC00~ 0xDFFF 间的 16-bit 编码单元,在 UTF-16 中被用作代理对的第二个编码单元。(See definition D74 in Section 3.8, Surrogates.)

2.3 UTF-32 CEF

UTF-32 编码模式 (Encoding Form):一种 Unicode 编码模式,会为每个 Unicode 标量值分配一个唯一的无符号 32-bit 编码单元(编码单元的值与 Unicode 标量值相等)。(See definition D90 in Section 3.9, Unicode Encoding Forms.)

UTF-32 虽可编码所有 Unicode 码点,但是相比其它编码模式会占用更多的空间。

3. UCS

UCS - Universal Character Set 通用字符集,由 International Standard ISO/IEC 10646 所规定,与 Unicode 标准相同。

UCS-2 :ISO/IEC 10646 编码模式,使用两个 8 位字节编码通用字符集,仅限于基本多语言平面,不能编码辅助平面。UCS-2 是固定宽度编码模式。tips:Notepad++ 支持 UCS-2 编码,如果在 UCS-2 编码的文件保存辅助平面中的字符,再次打开该文件时会发现辅助字符会变为另一个 BMP 字符,字符信息发生了丢失。

UCS-4 :ISO/IEC 10646 编码模式:使用 4 个 8 位字节编码通用字符集,适用于所有平面。

4. 相关术语补充

以下内容直接翻译自 Unicode 术语表:

  • Unicode 编码模式 (Unicode Encoding Form):一种字符编码模式,用于为每个 Unicode 标量值(scalar value)分别分配一个唯一的"编码单元序列"。Unicode 标准定义了三种 Unicode 编码模式:UTF-8, UTF-16, and UTF-32。(See definition D79 in Section 3.9, Unicode Encoding Forms.)

  • 字符编码模式 (Character Encoding Form):简称编码模式,将字符集中的定义(definition)映射到表示数据的实际编码单元。另外,Encoding Form 与 character encoding form 同义

  • 转换格式 (Transformation Format):从已编码字符序列到唯一编码序列的映射(typically bytes)。

  • 代理码点 (Surrogate Code Point):位于 U+D800 ~ U+DFFF 之间的 Unicode 码点属于作代理码点,保留共 UTF-16 使用。UTF-16 使用一对代理编码单元"表示"辅助码点。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容