为什么需要在UTF-8中标记连续字节?

问题描述 投票:0回答:3

我最近在阅读 UTF-8 可变宽度编码,我发现很奇怪,UTF-8 将每个连续字节的前两位指定为 10。

 Range           |  Encoding
-----------------+-----------------
     0 - 7f      |  0xxxxxxx
    80 - 7ff     |  110xxxxx 10xxxxxx
   800 - ffff    |  1110xxxx 10xxxxxx 10xxxxxx
 10000 - 10ffff  |  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

我正在尝试其他可能的可变宽度编码,发现通过使用以下方案,最多需要 3 个字节来存储所有 Unicode。如果第一位是 1,则该字符至少会再编码一个字节(读取直到第一位是 0)。

 Range           |  Encoding
-----------------+-----------------
     0 - 7f      |  0xxxxxxx
    80 - 407f    |  1xxxxxxx 0xxxxxxx
  4080 - 20407f  |  1xxxxxxx 1xxxxxxx 0xxxxxxx

UTF-8 中的连续位真的那么重要吗?第二种编码似乎更有效。

unicode utf-8 character-encoding utf
3个回答
15
投票

UTF-8 是自我验证的,前进速度快,后退也更容易。

自验证:由于序列中的第一个字节指定了长度,因此接下来的 X 个字节必须适合

10xxxxxx
,否则序列无效。单独看到一个
10xxxxxx
字节就可以立即识别为无效。
您建议的编码没有内置验证。

快速前进:如果必须跳过该字符,可以立即跳过第一个字节确定的 X 个字节,而不必检查每个中间字节。

更容易后退:如果您必须向后读取字节,您可以立即通过

10xxxxxx
识别连续字符。然后,您将能够向后扫描
10xxxxxx
字节以获取
11xxxxxx
前导字节,而无需扫描前导字节。

请参阅维基百科上的UTF-8 无效序列和错误处理


4
投票

除了已经提到的易于迭代之外:UTF-8 的目标是让基于 ASCII 的(和其他不支持 UTF-8 的)工具安全地处理搜索、串联、替换和转义等常见操作。

ASCII 兼容性对于互操作和安全性的优势超过了为字符 U+0800 到 U+407F 使用额外字节的成本。

80 - 407f | 1xxxxxx 0xxxxxxx

因此,有一些东亚多字节编码这样做,但产生了一些不幸的结果,而 UTF-8 专门试图避免这些结果。

在这个提议的方案中,连续字节现在与 ASCII 重叠,并且许多 ASCII 字符对于不同的语言和工具具有特殊含义。因此,如果您想说

¢
,那就是 0x80,0x27,而对于任何操作字节字符串的工具来说,它的第二个字节看起来像是
"
,而不支持该数据使用的建议编码。

在将用户输入结合到控制流的所有内容中提示安全漏洞。查询中的 SQL 注入、网页中的 HTML 注入、shell 脚本中的命令注入等等。

(东亚多字节编码并不像这里的编码那么糟糕,因为它们没有重用 ASCII 控制代码作为连续字节。按照建议,使用这种编码的文本不能存储在 C 空终止中例如,字符串,但 Shift-JIS 和朋友造成了一大堆安全漏洞,我们都很高兴摆脱它们。)


3
投票

使用您提出的方案,如果您查看字节编码的 0xxxxxxx,您无法判断这是单字节单元 0x00..0x7F 还是多字节单元的最后一个字节。 您必须向后扫描并查看前面的字节才能知道(并且您必须向后检查两个单元以查看这是否是 2 或 3 字节代码点的最后一个字节)。 如果你有一个 1xxxxxxx 字节,你无法判断它是多字节单元的第一个字节还是中间字节。 同样,你必须向后扫描。

相比之下,UTF-8 方案允许您告诉任何非连续字节有多少后续字节是代码点的一部分。 对于连续字节,您只需向后扫描到起始字节。 您还可以进行错误检查; UTF-8 中有很多无效序列,这实际上是一个好处。 (字节 0xC0、0xC1、0xF5..0xFF 不能出现在有效的 UTF-8 中。)

© www.soinside.com 2019 - 2024. All rights reserved.