我已经阅读了很多文章以了解 Unicode 代码点的最大数量,但我没有找到最终答案。
我知道 Unicode 代码点已最小化,以使所有 UTF-8 UTF-16 和 UTF-32 编码都能够处理相同数量的代码点。但是这个代码点的数量是多少?
我遇到的最常见的答案是 Unicode 代码点在 0x000000 到 0x10FFFF (1,114,112 个代码点)的范围内,但我也在其他地方读到它是 1,112,114 个代码点。那么是否有一个数字可以给出,或者问题是否比这更复杂?
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个非字符。这些在勘误 #9中有部分定义:U+nFFFE 和 U+nFFFF 形式的 34 个值(其中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 之外的值多语言平面,即范围 U+0000 .. U+FFFF。
是的,所有无法以 UTF-16 表示的代码点(包括使用代理项)都已被声明为无效。
U+10FFD 似乎是最高的代码点,但代理项 U+00FFFE 和 U+00FFFF 不是可用的代码点,因此总计数要低一些。
我做了一个很小的例程,在屏幕上打印一个很长的表格,从 0 到 n 值,其中 var start 是一个可由用户自定义的数字。这是片段:
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.fromCharCode和String.fromCodePoint的行为。请注意,第一个语句到达 4294967294,但输出每 65536 重复一次(16 位 = 2^16)。最后一个在代码 1114111 处停止工作(因为 Unicode 字符和符号列表从 0 开始,我们总共有 1,114,112 个 Unicode 代码点,但正如在其他答案中所说,并非所有这些都是有效的,因为它们是空点) . 还要记住,要使用某个 unicode char,您需要有一个适当的字体,其中定义了相应的 char。如果不是,您将显示一个空的 unicode 字符或一个空的方形字符。
我注意到在某些使用 Android 版 Chrome 浏览器的 Android 系统中,js 会String.fromCodePoint
为所有代码点返回错误。