为什么UTF-8在其编码中浪费了几位


17

根据Wikipedia的文章,UTF-8具有以下格式:

首码尾码字节字节1字节2字节3字节4
点点使用
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 07FF 2 110xxxxx 10xxxxxx
U + 0800 U + FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
U + 10000 U + 1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
x表示该位用于选择代码点。

这在每个连续字节上浪费了两位,而在第一个字节上浪费了一位。为什么未对UTF-8进行以下编码?

首码尾码字节字节1字节2字节3
点点使用
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 3FFF 2 10xxxxxx xxxxxxxx
U + 0800 U + 1FFFFF 3 110xxxxx xxxxxxxx xxxxxxxx

当代码点超出基本多语言平面或代码点在[U + 800,U + 3FFF]范围内时,它将节省一个字节。

为什么未以更有效的方式对UTF-8进行编码?


3
cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt您建议的编码与原始FSS / UTF建议相似。肯·汤普森(Ken Thompson)和罗伯·派克(Rob Pike)想要自同步属性。
ninjalj 2015年

4
另外,您的编码似乎不能保证ASCII代码值不会出现在非ASCII字符表示的任何部分中。FSS / UTF和UTF-8旨在与旧版程序配合使用(例如:那些使用ASCII NUL和斜杠(路径分隔符)作为分隔符的程序)。
ninjalj 2015年

Answers:


26

这样做是为了使您可以检测到何时处于多字节序列的中间。查看UTF-8数据时,您知道,如果看到10xxxxxx,则说明您处于多字节字符的中间,应该备份到流中,直到看到0xxxxxx或为止11xxxxxx。使用您的方案,字节2或3可能很容易以诸如0xxxxxxx11xxxxxx

还请记住,保存多少完全取决于您要编码的字符串数据类型。对于大多数文本,即使是亚洲文本,也很少会看到带有普通文本的四字节字符。而且,人们对文本外观的幼稚估计常常是错误的。我已经为UTF-8本地化了文本,其中包括日文,中文和韩文字符串,但实际上是俄语占用了最多的空间。(因为我们的亚洲字符串中经常会穿插罗马字符以表示专有名称,标点符号等,并且因为平均中文单词是1-3个字符,而平均俄语单词是很多很多。)


但是对于我来说,如果您从一个字符乞讨的位置开始,那么您就可以知道字符中有多少个字节,然后转到下一个字符乞求。
qbt937 2014年

11
当然。您的方案信息密集得多,但没有UTF-8提供的重要功能。通常,人们更喜欢安全性,这就是为什么可以使用UTF-8的原因。此外,要真正证明您的方案实际上更有效,您需要使用真实文本提供统计信息。您可能会发现,在大多数真实的文本中,您的方案可以节省非常少的数量,因此节省是不值得的。
机器人

3
另一个重要特征:如果没有嵌入的零代码点,则字符串中没有嵌入的零。
Deduplicator 2015年

对于泰语脚本,您需要允许每个打印字符4个字节。他们不仅迟到了派对,还拥有了一个高编号的密码小组。许多看起来像一个字符的东西实际上是由三个不同的unicode字符组成的。
詹姆斯·安德森

@ qbt937:使用您的方案,如何快速扫描以发现一个字符串是否包含另一个?
超级猫

6

官方方法让解码器知道它何时位于元组的中间,并且知道跳过字节(或向后),直到字节以0或开头11。当单个字节损坏时,这可以防止垃圾值。


3

简短的回答,您的建议不区分第一个字节和继续字节。

第一个字节高端的位模式可以告诉您构建实际字符的字节数。这些模式在解析字符串时还提供了一些错误识别。如果您正在读取(看似)字符的第一个字节,并且得到10xxxxxx,则说明您不同步。


2

没有提到的是,如果您具有正确的代码点序列,并且保证可以指向代码点的第一个字节的指针,那么使用UTF-8可以很容易地找到指向第一个字节的指针上一个代码点的字节数(跳过所有以01xx xxxx开头的字节)。使用您的编码,就不可能不检查字符串开头的所有字节。

考虑(2n + 2)个字节的序列

0xxxxxxx
n times (10xxxxxx, 10xxxxxx)
0xxxxxxx

n times (10xxxxxx, 10xxxxxx)
(10xxxxxx, 0xxxxxxx)

如果在此序列之后有指向第一个代码点的第一个字节的指针,则必须检查所有字节以找出最后一个代码点是0xxxxxxx还是(10xxxxxx,0xxxxxxx)。

实际上,存在更有效的编码方案,其中可以在恒定时间内完成到前一个代码点的访问,并且可以固定指向代码点中间的指针。允许以下代码:

X where X < 128
YX where 128 ≤ Y < 236, X < 128
ZYY where 236 ≤ Z < 256, 0 ≤ Y < 236. 

如果前三个字节之一≥236,则它是3字节序列的开始,因为在任何有效的3字节序列中都不能有两个这样的字节。否则,如果前两个字节之一≥128,则它是两个字节序列的开始。否则,前一个字节是单个字节<128。

搜索子字符串变得稍微困难​​一些。您可能希望排除零字节,以便如果字符串包含零代码点,则字符串仅包含零字节。


没有提到什么… –并非真的如此,因为这直接来自@ratchet freak的回答中的观察。
Piotr Dobrogost,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.