Unicode 可以映射多少个字符?
Posted
技术标签:
【中文标题】Unicode 可以映射多少个字符?【英文标题】:How many characters can be mapped with Unicode? 【发布时间】:2011-08-20 21:55:43 【问题描述】:我要求计算 Unicode 中所有可能的有效组合并附上解释。我知道一个 char 可以编码为 1、2、3 或 4 个字节。我也不明白为什么连续字节有限制,即使那个字符的起始字节清除了它应该有多长。
【问题讨论】:
【参考方案1】:我要求计算 Unicode 中所有可能的有效组合并附上解释。
1,111,998:17 个平面 × 每个平面 65,536 个字符 - 2048 个代理项 - 66 个非字符
请注意,UTF-8 和 UTF-32 理论上可以编码超过 17 个平面,但范围受限于 limitations of the UTF-16 encoding。
137,929 个代码点实际上是在Unicode 12.1 中分配的。
我也不明白为什么连续字节有限制,即使那个字符的起始字节清除了它应该有多长。
UTF-8 中这个限制的目的是为了使编码self-synchronizing。
举个反例,考虑中文GB 18030 encoding。在那里,字母ß
表示为字节序列81 30 89 38
,其中包含数字0
和8
的编码。因此,如果您的字符串搜索功能不是针对这种特定于编码的怪癖而设计的,那么搜索数字 8
会在字母 ß
中发现误报。
在 UTF-8 中,这不会发生,因为前导字节和尾随字节之间的不重叠保证了较短字符的编码永远不会发生在较长字符的编码中。
【讨论】:
您链接的“自同步”文章根本没有解释什么是自同步 有趣的是,UTF8 只需要 4 个字节即可映射所有 Unicode 字符,但如果需要,UTF8 最多可以支持 680 亿个字符,每个字符最多占用 7 个字节。跨度> 【参考方案2】:Unicode 允许 17 个planes,每个字符有 65,536 个可能的字符(或“代码点”)。这给出了总共 1,114,112 个可能的字符。目前,仅分配了大约 10% 的空间。
这些代码点如何编码的确切细节因编码而异,但您的问题听起来像是您在考虑 UTF-8。限制连续字节的原因大概是这样很容易找到下一个字符的开头(因为连续字符总是采用 10xxxxxx 的形式,但起始字节永远不会是这种形式)。
【讨论】:
根据这些“平面”,即使是 4 字节字符的最后三个字节也可以表示其中的 64 个。我错了吗? 是的,就是同步的,见cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt 我认为这已经过时了。它不再使用 6 个字节 @Andy:这是有道理的:UTF-8 的原始规范适用于更大的数字。 21 位的限制对于那些将自己锁定在 16 位字符中的人来说是一个安慰,因此 UCS-2 产生了被称为 UTF-16 的可恶。 @Simon:有 34 个非字符代码点,当按位添加 0xFFFE == 0xFFFE 时,每个平面有两个这样的代码点。此外,在 0x00_FDD0 .. 0x00_FDEF 范围内有 31 个非字符代码点。另外,您应该从中减去代理项,由于 UTF-16 缺陷,这些代理项对于开放交换是不合法的,但必须在您的程序内部得到支持。【参考方案3】:Unicode 支持 1,114,112 个代码点。有 2048 个代理代码点,给出 1,112,064 个标量值。其中,有 66 个非字符,导致 1,111,998 个可能的编码字符(除非我计算错误)。
【讨论】:
你能看看我的回答吗?为什么有 1,112,114 个代码点? 这个数字来自使用 UTF-16 代理系统可寻址的平面数。您有 1024 个低代理和 1024 个高代理,提供 1024² 个非 BMP 代码点。这加上 65,536 个 BMP 代码点正好是 1,114,112。 @Philipp,但您在回答中给出了“1_112_114”,但您在评论中解释了“1_114_112”。也许你把 2 和 4 弄混了。 这个答案多年来一直存在计算错误,所以我冒昧地清理了它。是的,答案中的值 1112114 是一个错字。正确的值为1114112,也就是0x110000的十进制值。【参考方案4】:要给出一个比喻准确的答案,all of them
。
UTF-8 编码中的连续字节允许在面对“线路噪声”时重新同步编码的八位字节流。编码器,只需要向前扫描一个在 0x80 和 0xBF 之间没有值的字节,就知道下一个字节是一个新字符点的开始。
理论上,今天使用的编码允许表达 Unicode 字符数最长为 31 位的字符。实际上,这种编码实际上是在 Twitter 等服务上实现的,其中最大长度的推文可以编码多达 4,340 位的数据。 (140 个字符[有效和无效],每次 31 位。)
【讨论】:
其实理论上不限于31位,64位机器上可以做大。perl -le 'print ord "\x1FFF_FFFF_FFFF"'
在 64 位机器上打印出 35184372088831,但在 32 位机器上给出整数溢出。你可以在你的 perl 程序中使用更大的字符,但是如果你尝试将它们打印为 utf8,你会得到一个强制警告,除非你禁用它:perl -le 'print "\x1FFF_FFFF"' Code point 0x1FFFFFFF is not Unicode, may not be portable at -e line 1. ######
。 “loose utf8”和“strict UTF-8”是有区别的:前者不受限制。
今天使用的编码不允许 31 位标量值。 UTF-32 将允许 32 位值,UTF-8 甚至更多,但 UTF-16(由 Windows、OS X、Java、.NET、Python 内部使用,因此是最流行的编码方案)允许超过一百万(应该足够了)。
“所有这些”不太准确;传统编码中的某些字符不在 Unicode 中。例如,MacRoman 中的 Apple 标志,以及 ATASCII 中的几个图形字符。 OTOH,有一个私人使用区,所以这些字符可以用 Unicode 映射;它们只是不属于标准的一部分。
@tchrist:Python 3 确实使用 UTF-16;例如,在我的系统上,我可以说len(chr(0x10000))
,给出 2(代码单元)。 OS X 的内核使用 UTF-8,没错,但高级 API(Cocoa 等)使用 UTF-16。
@Philip:我只使用 Python 2,它的 Unicode 支持还有很多不足之处。我是系统专家,所以我不做最终用户镀铬:我在 OS X 上使用的所有系统调用都采用 UTF-8,内核会为你转换成 NFC。我在 Java 中的 UTF-16 体验一直很糟糕:尝试使用正则表达式括号字符类匹配其中的一些非 BMP 代码点,例如 [?-?]
,你就会明白为什么我发现暴露 UTF-16 是个垃圾。让程序员思考编码形式而不是逻辑字符是错误的。【参考方案5】:
Unicode 的十六进制数是 110000,即 1114112
【讨论】:
【参考方案6】:根据Wikipedia,Unicode 12.1(2019 年 5 月发布)包含 137,994 个不同的字符。
【讨论】:
@Ufuk:Unicode 没有字符。它有代码点。有时它需要多个代码点来组成一个字符。例如,字符“5̃”是两个代码点,而字符“ñ”可能是一个或两个代码点(或更多!)。有 2²¹ 个可能的代码点,但其中一些保留为非字符或部分字符。 Unicode 是一种字符编码标准。 unicode.org/faq/basic_q.html 的第一个回答:“Unicode 是通用字符编码”,所以说“Unicode 不是编码”是错误的。 (我自己曾经犯过这个错误。) @tchrist:Unicode 标准定义了多个术语,其中包括“抽象字符”和“编码字符”。所以说 Unicode 没有字符也是不正确的。以上是关于Unicode 可以映射多少个字符?的主要内容,如果未能解决你的问题,请参考以下文章