Есть ли в Unicode определенное максимальное количество кодовых точек?

Я прочитал много статей, чтобы узнать, каково максимальное количество кодовых точек Unicode, но окончательного ответа не нашел.

Я понял, что кодовые точки Unicode были сведены к минимуму, чтобы все кодировки UTF-8 UTF-16 и UTF-32 могли обрабатывать одинаковое количество кодовых точек. Но каково это количество кодовых точек?

Наиболее частый ответ, с которым я сталкивался, заключается в том, что кодовые точки Unicode находятся в диапазоне от 0x000000 до 0x10FFFF (1 114 112 кодовых точек), но я также читал в других местах, что это 1 112 114 кодовых точек. Так нужно ли давать одно число или проблема сложнее?


person Community    schedule 11.12.2014    source источник
comment
возможный дубликат Сколько символов можно сопоставить с Unicode?   -  person Jonathan Leffler    schedule 11.12.2014


Ответы (3)


Максимально допустимая кодовая точка в 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. Это 2048 кодовых точек, зарезервированных для UTF-16.

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

Есть также 66 несимволов. Они частично определены в исправлении № 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. Среди прочего, во Введении говорится:

Стандарт Unicode, версия 7.0, содержит 112 956 символов.

Таким образом, было выделено только около 10% доступных кодовых точек.

Я не могу объяснить, почему вы нашли 1 112 114 в качестве числа кодовых точек.

Между прочим, верхний предел U+10FFFF выбран таким образом, чтобы все значения в Unicode могли быть представлены в одной или двух 2-байтовых единицах кодирования в UTF-16, используя один старший суррогат и один младший суррогат для представления значений вне BMP или Basic. Многоязычная плоскость, которая находится в диапазоне U+0000 .. U+FFFF.

person Jonathan Leffler    schedule 11.12.2014
comment
1 112 114 выглядят как опечатка, это счет 000000..10FFFF с переставленными 2 и 4. - person user313114; 11.12.2014
comment
@ user313114: Я полагаю, что это может быть составная опечатка, как вы предполагаете; это по крайней мере лучше, чем отсутствие объяснений (примерно то, что у меня есть на данный момент). Я мог бы попытаться учесть (немного) меньшее количество символов, чем 1 112 064, но не чуть большее. - person Jonathan Leffler; 11.12.2014
comment
См. ответ Филиппа: stackoverflow.com/questions/5924105/ - person ; 11.12.2014
comment
@JonathanLeffler Я полагаю, что в этом ответе может быть древняя опечатка. В частности, значения от 0x11000 до 0x1FFFF недействительны... я считаю, что диапазон должен быть от 0x110000 до 0x1FFFFF (т. е. в обоих числах отсутствует цифра). Это имеет больше смысла с вашим объяснением, поскольку последний диапазон представляет 21-битные целые числа, которые не являются допустимыми кодовыми точками, а тот, что в вашем ответе, включает допустимые кодовые точки. - person ravron; 19.12.2018
comment
@ravron: ты прав; Спасибо. Я исправил это, я думаю/надеюсь. - person Jonathan Leffler; 19.12.2018

Да, все кодовые точки, которые не могут быть представлены в UTF-16 (включая использование суррогатов), объявлены недействительными.

U+10FFD кажется самой высокой кодовой точкой, но суррогаты, U+00FFFE и U+00FFFF не являются пригодными для использования кодовыми точками, поэтому общее количество немного ниже.

person user313114    schedule 11.12.2014

Я сделал очень маленькую подпрограмму, которая выводит на экран очень длинную таблицу со значениями от 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) функция неумолимо останавливается, поэтому я предполагаю, что она достигла своего максимально возможного значения: поэтому я интерпретирую это как максимально возможное значение кодовой таблицы символов Юникода. Конечно, как сказано в других ответах, не весь код char имеет эквивалентные символы, но часто они пусты, как показано в примере. Также есть много символов, которые повторяются несколько раз в разных точках от 0 до 4294967294 кодов символов.

Изменить: улучшения

(спасибо @duskwuff)

Теперь также можно сравнить поведение String.fromCharCode и String.fromCodePoint. Обратите внимание, что первый оператор получает значение 4294967294, но вывод повторяется каждые 65536 (16 бит = 2^16). Последний перестает работать с кодом 1114111 (поскольку список символов и символов Юникода начинается с 0, у нас всего 1 114 112 кодовых точек Юникода, но, как сказано в других ответах, не все из них действительны в том смысле, что они пустые точки) . Также помните, что для использования определенного символа Юникода вам нужен соответствующий шрифт, в котором определен соответствующий символ. Если нет, вы покажете пустой символ юникода или пустой квадратный символ.

введите здесь описание изображения

Уведомление:

Я заметил, что в некоторых системах Android, использующих браузер Chrome для Android, js String.fromCodePoint возвращает ошибку для всех кодовых точек.

person willy wonka    schedule 16.10.2016
comment
К сожалению, результаты вашей функции неверны. String.fromCharCode усекает ввод до 16 бит; старшие 16 бит ввода, которые вы передаете, игнорируются. - person ; 17.10.2016
comment
О, спасибо за уведомление. Я не знал. Как мне это исправить? - person willy wonka; 17.10.2016
comment
Вместо этого используйте String.fromCodePoint. И не пытайтесь перейти выше кодовой точки 0x10FFFF. - person ; 17.10.2016
comment
попробовал локально: подпрограмма выдает ошибку после 1114111 и перестает работать. Могу я спросить, почему? Ошибка: Uncaught RangeError: Invalid code point [обработанный номер] - person willy wonka; 18.10.2016
comment
1114111 — это 0x10FFFF. Unicode определяет это как максимальную кодовую точку, поэтому попытка использовать более высокую кодовую точку приведет к ошибке. - person ; 18.10.2016
comment
@duskwuff. Хорошо, я сделал несколько улучшений: теперь можно сравнивать как String.fromCharCode, так и String.fromCodePoint. - person willy wonka; 18.10.2016
comment
Могу ли я внести дополнительные улучшения в свой ответ? - person willy wonka; 06.01.2017
comment
Вы можете попробовать, но я бы не рассчитывал, что это поможет. Ответ, основанный на ссылках на стандарты (например, принятый ответ Джонатана Леффлера выше), намного лучше, чем ответ, основанный на наблюдениях и догадках. - person ; 06.01.2017
comment
@duskwuff Согласен, тем не менее каждый ответ проясняет некоторые аспекты одной и той же проблемы. Поэтому я рассматриваю их как взаимодополняющие, а не как соперники. В любом случае, как я могу улучшить свой ответ? - person willy wonka; 13.01.2017
comment
Хороший альтернативный ответ. Вы не заслуживаете отрицательных голосов. Вы потратили много времени на этот ответ. Я хочу, чтобы больше людей увидело это. - person Jack Giffin; 20.04.2020