Unicode 是不是有定义的最大代码点数?

Posted

技术标签:

【中文标题】Unicode 是不是有定义的最大代码点数?【英文标题】:Does Unicode have a defined maximum number of code points?Unicode 是否有定义的最大代码点数? 【发布时间】:2015-02-09 12:41:16 【问题描述】:

我已经阅读了很多文章以了解 Unicode 码位的最大数量,但我没有找到最终答案。

我了解到,Unicode 代码点已最小化,以使所有 UTF-8 UTF-16 和 UTF-32 编码都能够处理相同数量的代码点。但是这个代码点的数量是多少?

我遇到的最常见的答案是 Unicode 代码点在 0x000000 到 0x10FFFF 的范围内(1,114,112 个代码点),但我也在其他地方读到它是 1,112,114 个代码点。那么是否有一个数字可以给出,或者问题是否比这更复杂?

【问题讨论】:

How many characters can be mapped with Unicode?的可能重复 【参考方案1】:

是的,所有无法以 UTF-16 表示的代码点(包括使用代理项)都已被声明为无效。

U+10FFD 似乎是最高的代码点,但代理项 U+00FFFE 和 U+00FFFF 不是可用的代码点,因此总计数要低一些。

【讨论】:

【参考方案2】:

Unicode 中的最大有效代码点为 U+10FFFF,这使其成为 21 位代码集(但并非所有 21 位整数都是有效的 Unicode 代码点;特别是从 0x110000 到 0x1FFFFF 的值不是有效的 Unicode 代码点)。

这就是数字 1,114,112 的来源:U+0000 .. U+10FFFF 是 1,114,112 个值。

但是,还有一组代码点可以替代 UTF-16。这些在 U+D800 .. U+DFFF 范围内。这是为 UTF-16 保留的 2048 个代码点。

1,114,112 - 2,048 = 1,112,064

还有 66 个非字符。这些部分在Corrigendum #9 中定义:34 个 U+nFFFE 和 U+nFFFF 形式的值(其中 n 是值 0x00000、0x10000、... 0xF0000、0x100000)和 32 个值 U+ FDD0 - U+FDEF。减去这些也会产生 1,111,998 个可分配字符。为“私人使用”保留了三个范围:U+E000 .. U+F8FF、U+F0000 .. U+FFFFD 和 U+100000 .. U+10FFFD。实际分配的值的数量取决于您正在查看的 Unicode 版本。您可以在Unicode Consortium 找到有关最新版本的信息。除其他外,那里的介绍说:

Unicode 标准 7.0 版包含 112,956 个字符

因此只分配了大约 10% 的可用代码点。

我无法解释为什么您发现 1,112,114 作为代码点的数量。

顺便说一句,选择上限 U+10FFFF 是为了使 Unicode 中的所有值都可以用一个或两个 UTF-16 中的 2 字节编码单元表示,使用一个高代理和一个低代理来表示超出范围的值BMP 或 Basic Multilingual Plane,即 U+0000 .. U+FFFF 范围。

【讨论】:

1,112,114 看起来像一个错字,它是 000000..10FFFF 计数与 2 和 4 转置。 @user313114:我想这可能是您建议的复合错字;这至少比没有解释要好(这大致是我目前所得到的)。我可以努力解释(略)比 1,112,064 少的字符数,但不能解释稍大的字符数。 查看 Philipp 的回答:***.com/questions/5924105/… @JonathanLeffler 我相信这个答案可能有一个古老的错字。在“……特别是从 0x11000 到 0x1FFFF 的值无效……”中,我认为范围应该是从 0x110000 到 0x1FFFFF(即两个数字都缺少一个数字)。这对您的解释更有意义,因为后一个范围表示不是有效代码点的 21 位整数,而您的答案中包含 valid code points。 @ravron:你是对的;谢谢。我想/希望我已经修好了。【参考方案3】:

我做了一个很小的例程,在屏幕上打印一个很长的表格,从 0 到 n 值,其中 var start 是一个可由用户自定义的数字。这是sn-p:

function getVal()
			
				var start = parseInt(document.getElementById('start').value);
				var range = parseInt(document.getElementById('range').value);
				var end = start + range;
				return [start, range, end];
			

		
			function next()
			
				var values = getVal();
				document.getElementById('start').value = values[2];
				document.getElementById('ok').click();
			
			
			function prev()
			
				var values = getVal();
				document.getElementById('start').value = values[0] - values[1];
				document.getElementById('ok').click();
			
			
			function renderCharCodeTable()
			
				var values = getVal();
				var start = values[0];
				var end = values[2];

				const MINSTART = 0; // Allowed range
				const MAXEND = 4294967294; // Allowed range
				
				start = start < MINSTART ? MINSTART : start;
				end = end < MINSTART ? (MINSTART + 1) : end;

				start = start > MAXEND ? (MAXEND - 1) : start;
				end = end >= MAXEND ? (MAXEND + 1) : end;
				
				var tr = [];
				
				var unicodeCharSet = document.getElementById('unicodeCharSet');

				var cCode;
				var cPoint;
				for (var c = start; c < end; c++)
				
					try
					
						cCode = String.fromCharCode(c);
					
					catch (e)
					
						cCode = 'fromCharCode max val exceeded';
					
					
					try
					
						cPoint = String.fromCodePoint(c);
					
					catch (e)
					
						cPoint = 'fromCodePoint max val exceeded';
					
					
					tr[c] = '<tr><td>' + c + '</td><td>' + cCode + '</td><td>' + cPoint + '</td></tr>'
				
				unicodeCharSet.innerhtml = tr.join('');
			
			
			function startRender()
			
				setTimeout(renderCharCodeTable, 100);
				console.time('renderCharCodeTable');
			
			unicodeCharSet.addEventListener("load",startRender());
body
		
			margin-bottom: 50%;
		
		
		form
		
			position: fixed;
		
		
		table *
		
			border: 1px solid black;
			font-size: 1em;
			text-align: center;
		
		
		table
		
			margin: auto;
			border-collapse: collapse;
		
		
		td:hover
		
			padding-bottom: 1.5em;
			padding-top: 1.5em;
		
		
		tbody > tr:hover
		
			font-size: 5em;
		
	
	<form>
		Start Unicode: <input type="number" id="start" value="0" onchange="renderCharCodeTable()" min="0" max="4294967300" title="Set a number from 0 to 4294967294" >
		<p></p>
		Show <input type="number" id="range" value="30" onchange="renderCharCodeTable()" min="1" max="1000" title="Range to show. Insert a value from 10 to 1000" > symbols at once.
		<p></p>
		<input type="button" id="pr" value="◄◄" onclick="prev()" title="Mostra precedenti" >
		<input type="button" id="nx" value="►►" onclick="next()" title="Mostra successivi" >
		<input type="button" id="ok" value="OK" onclick="startRender()" title="Ok" >
		<input type="reset" id="rst" value="X" onclick="startRender()" title="Reset" >
		
	</form>
	<table>
		<thead>
			<tr>
				<th>CODE</th>
				<th>Symbol fromCharCode</th>
				<th>Symbol fromCodePoint</th>
			</tr>
		</thead>
		<tbody id="unicodeCharSet">
			<tr><td colspan="2">Rendering...</td></tr>
		</tbody>
	</table>

第一次运行它,然后打开代码并将start 变量的值设置为一个非常高的数字,比MAXEND 常量值低一点点。以下是我得到的:

    code        equivalent symbol
~~~ first execution output example ~~~~~

0   
1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  !
34  "
35  #
36  $
37  %
38  &
39  '
40  (
41  )
42  *
43  +
44  ,
45  -
46  .
47  /
48  0
49  1
50  2
51  3
52  4
53  5
54  6
55  7
56  8
57  9
~~~ second execution output example ~~~~~
4294967275  →
4294967276  ↓
4294967277  ■
4294967278  ○
4294967279  ￯
4294967280  ￰
4294967281  ￱
4294967282  ￲
4294967283  ￳
4294967284  ￴
4294967285  ￵
4294967286  ￶
4294967287  ￷
4294967288  ￸
4294967289  
4294967290  
4294967291  
4294967292  
4294967293  �
4294967294  

输出当然会被截断(在第一次和第二次执行之间),因为它太长了。

在 4294967294 (= 2^32) 之后,函数不可阻挡地停止,所以我认为它已经达到了它的最大可能值:所以我将其解释为 unicode char 代码表的最大可能值。当然,正如其他答案所说,并非所有字符代码都有等效的符号,但它们通常是空的,如示例所示。还有很多符号在 0 到 4294967294 个字符代码之间的不同点重复多次

编辑:改进

(感谢@duskwuff)

现在还可以比较 String.fromCharCodeString.fromCodePoint 行为。请注意,第一个语句到达 4294967294,但输出每 65536 重复一次(16 位 = 2^16)。最后一个在代码 1114111 处停止工作(因为 unicode char 和符号列表从 0 开始,我们总共有 1,114,112 个 Unicode 代码点,但正如在其他答案中所说,并非所有这些都是有效的,因为它们是空点) .还要记住,要使用某个 unicode char,您需要有一个适当的字体,其中定义了相应的 char。如果不是,您将显示一个空的 unicode 字符或一个空的方形字符。

注意:

我注意到,在某些使用 android 版 Chrome 浏览器的 Android 系统中,js String.fromCodePoint 会为所有代码点返回错误。

【讨论】:

很遗憾,您的函数的结果不正确。 String.fromCharCode 将其输入截断为 16 位;您传递的输入的高 16 位将被忽略。 哦,谢谢你的通知。我不知道。我该如何纠正它? 请改用String.fromCodePoint。并且不要尝试超过代码点 0x10FFFF。 1114111 是 0x10FFFF。 Unicode 将其定义为最大代码点,因此尝试使用更高的代码点会产生错误。 很好的替代答案。你不应该投反对票。你在这个答案上花了很多时间。我希望更多人能看到这一点。

以上是关于Unicode 是不是有定义的最大代码点数?的主要内容,如果未能解决你的问题,请参考以下文章

python unicode

laravel 5.4 运行 make:auth 报错

uni-app微信小程序开发添加iconfont图标字体

有没有办法以编程方式确定字体文件是不是具有特定的 Unicode 字形?

如何在 unicode 形式之间进行转换:字符串、名称、数字

python基础篇----字符串unicode