Unicode可以映射多少个字符?

97

我要求计算Unicode中所有可能有效组合的数量,附带说明。我知道一个字符可以编码为1、2、3或4个字节。我也不明白为什么连续字节有限制,即使该字符的起始字节清楚表明它的长度。

6个回答

132
我正在询问Unicode中所有可能有效组合的数量,附有解释。
1,111,998:17个平面×每个平面65,536个字符 - 2048个代理项 - 66个非字符
请注意,UTF-8和UTF-32理论上可以编码比17个平面更多的内容,但范围受到UTF-16编码的限制
Unicode 12.1中实际分配了137,929个代码点。
这种UTF-8限制的目的是使编码自同步
作为反例,考虑中文GB 18030编码。在那里,字母ß表示为字节序列81 30 89 38,其中包含数字08的编码。因此,如果您有一个未针对此编码特定问题设计的字符串搜索函数,则搜索数字8将在字母ß内产生误报。
在UTF-8中,这种情况不会发生,因为引导字节和尾随字节之间的非重叠区域保证了较短字符的编码永远不会出现在较长字符的编码中。

2
你链接的“自同步”文章根本没有解释什么是自同步。 - Pacerier
2
有趣的是,UTF8只需要4个字节来映射所有Unicode字符,但如果需要,UTF8可以支持高达680亿个字符,每个字符最多占用7个字节。 - santiago arizti
@santiagoarizti 嗯……不,它不能,直截了当地说。UTF-8只能在最多4个字节的工作空间中编码理论上的最大2,097,152个码点,一旦考虑到开销。然后,因为某些原因™(归咎于可耻的短视UTF-16混乱……),有63,487个码点被声明为无效,剩下理论上的2,033,665个码点。但是,由于UTF-8/16/32只是相同总体标准的不同编码方式,它们都被限制在1,181,820个可编码码点上以保持一致性。你可以设计一个新的非Unicode系统,类似于UTF-8,可以更高,但UTF-8本身不能。 - undefined

9
Unicode允许17个平面,每个平面有65536个可能的字符(或'码点')。这总共可以获得1114112个可能的字符。目前,只分配了大约10%的空间。
这些码点的精确细节因编码而异,但是您的问题似乎是关于UTF-8的。限制连续字节的原因可能是为了易于找到下一个字符的开头(因为连续字符始终采用10xxxxxx的形式,但起始字节永远不能采用此形式)。

根据这些“平面”,即使是4字节字符的最后三个字节也可以表示其中的64个。我错了吗? - Ufuk Hacıoğulları
是的,那是为了同步,参见http://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt。 - ninjalj
2
我认为那已经过时了。它不再使用6个字节。 - Ufuk Hacıoğulları
3
@Andy: 那很有道理:UTF-8的原始规范适用于更大的数字。21位的限制是为了迎合那些被困在16位字符中的人们,因此UCS-2诞生了被称为UTF-16的可憎物。 - tchrist
1
@Simon:有34个非字符代码点,即按位加上0xFFFE等于0xFFFE的任何内容,因此每个平面有两个这样的代码点。此外,在范围0x00_FDD0 .. 0x00_FDEF中有31个非字符代码点。另外,您还应从中减去代理项,由于UTF-16缺陷而不适用于开放交换,但必须在程序内支持。 - tchrist
显示剩余4条评论

7

Unicode支持1,114,112个码点。有2048个代理码点,共有1,112,064个标量值。其中有66个非字符,导致可能编码的字符数为1,111,998(除非我计算错误)。


你能看一下我的回答吗?为什么有 1,112,114 个代码点? - Ufuk Hacıoğulları
3
这个数字是使用UTF-16代理系统寻址的飞机数量。你有1024个低代理和1024个高代理,共计1024²个非BMP代码点。加上65,536个BMP代码点,总共正好是1,114,112个。 - Philipp
2
@Philipp,你在回答中给出了“1_112_114”,但在评论中解释的是“1_114_112”。也许你把2和4搞混了。 - Shawn Kovac
2
这个答案存在计算错误已经有很多年了,所以我冒昧进行了整理。是的,在答案中的1112114是一个笔误。正确的值是1114112,它是0x110000的十进制值。 - Ray Toal

2
根据维基百科,Unicode 12.1(于2019年5月发布)包含137,994个不同的字符。

@Ufuk:Unicode 没有字符,只有代码点。有时需要多个代码点来组成一个字符。例如,“5̃”这个字符是由两个代码点组成的,而“ñ”这个字符可能是一个或两个代码点(或更多!)。Unicode 有 2²¹ 种可能的代码点,但其中一些被保留为非字符或部分字符。 - tchrist
6
Unicode是一种字符编码标准。在http://www.unicode.org/faq/basic_q.html中,第一个回答是:“Unicode是通用字符编码”,因此说“Unicode不是编码”是错误的。(我曾经犯过这个错误。) - Philipp
1
@tchrist:Unicode标准定义了多个术语,其中包括“抽象字符”和“编码字符”。因此说Unicode没有字符也是不正确的。 - Philipp

1

用一个比喻来回答,所有的

UTF-8编码中的连续字节允许在“线路噪声”的情况下重新同步编码的八位字节流。编码器只需向前扫描一个没有0x80到0xBF之间值的字节,就可以知道下一个字节是新字符点的开始。

理论上,今天使用的编码允许表达Unicode字符号长达31位。实际上,在像Twitter这样的服务中实现了这种编码,最大长度的推文可以编码高达4,340位的数据。(140个字符[有效和无效],每个字符31位。)


实际上,在理论上不限于31位,你可以在64位机器上扩展。perl -le 'print ord "\x{1FFF_FFFF_FFFF}"' 在64位机器上输出35184372088831,但在32位机器上会出现整数溢出。您可以在perl程序中使用更大的字符,但如果尝试将它们作为utf8打印出来,则会得到强制警告,除非您禁用此类警告:perl -le 'print"\x{1FFF_FFFF}"'。 0x1FFFFFFF代码点不是Unicode,可能不可移植。 “松散的UTF-8”和“严格的UTF-8”之间存在差异:前者没有限制。 - tchrist
1
今天使用的编码不允许31位标量值。UTF-32可以允许32位值,UTF-8甚至可以允许更多,但是UTF-16(由Windows、OS X、Java、.NET、Python内部使用,因此是最流行的编码方案)只允许略超过一百万个(这应该仍然足够)。 - Philipp
1
“全部”并不完全准确;在传统编码中有一些Unicode中不存在的字符。例如,MacRoman中的苹果标志和ATASCII中的一些图形字符。 另一方面,有一个专用区域,因此这些字符可以使用Unicode进行映射;它们只是不属于标准部分。 - dan04
1
@tchrist:Python 3确实使用UTF-16;例如,在我的系统上,我可以说len(chr(0x10000)),得到2(代码单元)。OS X的内核使用UTF-8,但高级API(Cocoa等)使用UTF-16。 - Philipp
1
@Philip:我只使用Python 2,它的Unicode支持还有很大的改进空间。我是一个系统工程师,所以我不做最终用户的Chrome平台开发:在OS X上我使用的所有系统调用都采用UTF-8编码,内核会为你转换成NFC格式。我的Java UTF-16编码经验很糟糕:尝试一下使用正则表达式匹配非BMP代码点的字符类,例如[-],你就会明白为什么我认为暴露UTF-16编码是一个失败的尝试。让程序员思考编码形式而不是逻辑字符是一个错误。 - tchrist
显示剩余3条评论

0

Unicode 的十六进制数为 110000,即 1114112。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接