Подтвердить что ты не робот

Как Java хранит символы UTF-16 в 16-разрядном типе char?

В соответствии с спецификацией Java SE 7 Java использует стандарт Unicode UTF-16 для представления символов. Представляя String как простой массив из 16-битных переменных, каждый из которых содержит один символ, жизнь проста.

К сожалению, есть кодовые точки, для которых 16 бит просто недостаточно (я считаю, что это 16/17-й из всех символов Unicode). Таким образом, в String это не представляет никакой прямой проблемы, потому что, когда вы хотите сохранить один из этих символов ~ 1.048.576 с использованием дополнительных двух байтов, будут использоваться только две позиции в этом String.

Это, без какой-либо прямой проблемы, работает для String s, потому что всегда могут быть дополнительные два байта. Хотя, когда речь идет о одиночных переменных, которые в отличие от кодировки UTF-16 имеют фиксированную длину 16 бит, как эти символы могут быть сохранены, и, в частности, как это делает Java со своим 2-байтным "char"?

4b9b3361

Ответ 1

Ответ находится в javadoc:

Тип данных char (и, следовательно, значение, которое имеет объект Character инкапсуляция) основаны на исходной спецификации Юникода, которая определенные символы как 16-битные объекты фиксированной ширины. Юникод с тех пор этот стандарт был изменен, чтобы для представления требуется более 16 бит.

Диапазон юридического кода точки теперь U + 0000 до U + 10FFFF, известный как скалярное значение Unicode. (Обратитесь к определению нотации U + n в стандарте Unicode.) Набор символов от U + 0000 до U + FFFF иногда упоминается как базовый многоязычный самолет (BMP). Персонажи, чьи кодовые точки больше U + FFFF, называются дополнительными символами. Java 2 использует представление UTF-16 в массивах char и в String и StringBuffer. В этом представлении дополнительные символы представлены в виде пары значений char, первая из диапазон высоких суррогатов, (\ uD800-\uDBFF), второй из диапазон низких суррогатов (\ uDC00-\uDFFF).

A char значение, следовательно, представляет собой базовые многоязычные плоскости (BMP), в том числе суррогатные кодовые точки или кодовые единицы кодировки UTF-16. Int значение представляет все кодовые точки Unicode, включая дополнительный код точки. Нижние (наименее значимые) 21 бит int используются для представляют собой кодовые точки Unicode и верхние (наиболее значимые) 11 бит должен быть равен нулю.

Если не указано иное, поведение по отношению к дополнительные символы и суррогатные значения char таковы: методы, принимающие только значение char, не могут поддерживать дополнительные персонажи. Они рассматривают значения char из суррогатных диапазонов как undefined символов. Например, Character.isLetter('\ uD840') возвращает false, хотя это конкретное значение, за которым следует любое низкое суррогатное значение в строке будет представлять собой букву. Методы которые принимают значение int, поддерживают все символы Unicode, включая дополнительные символы. Например, Character.isLetter(0x2F81A) возвращает true, потому что значение кодовой точки представляет собой букву (CJK иероглиф). В документации API Java SE кодовая точка Unicode используется для значений символов в диапазоне между U + 0000 и U + 10FFFF, и юникодный код используется для 16-разрядных значений char, которые являются кодом единиц кодировки UTF-16. Для получения дополнительной информации о Unicode терминологии, обратитесь к Глоссарию Unicode.

Просто сказано:

  • 16 бит для правила char были разработаны для старой версии стандарта Unicode
  • вам иногда нужны два символа для представления руны юникода (кодовая точка), которая не находится в базовой многоязычной плоскости. Этот вид "работает", потому что вы не часто используете символы, особенно для обработки юникодовых рун вне BMP.

Еще проще сказать:

  • java char не представляет кодовый код Unicode (ну, не всегда).

В стороне, можно отметить, что эволюция Unicode для продолжения BMP сделала UTF-16 глобально нерелевантным, теперь, когда UTF-16 даже не позволяет фиксировать отношение байт-символов. Вот почему более современные языки основаны на UTF-8. Этот манифест помогает понять его.

Ответ 2

В принципе, строки хранят последовательность кодовых блоков UTF-16... что не совпадает с сохранением последовательности кодовых точек Unicode.

Если требуется символ за пределами базовой многоязыковой плоскости, в нем есть два блока кода UTF-16 в пределах String.

Большинство операций String - length(), charAt, substring() и т.д. обрабатывают номера кодовых блоков UTF-16. Тем не менее, существуют такие операции, как codePointAt(), который будет обрабатывать полные кодовые точки Юникода... хотя индексы все еще выражаются в терминах UTF- 16 единиц кода.

EDIT: если вы хотите сохранить кодовую точку, отличную от BMP, в одном char, вам в основном не повезло. Это похоже на желание сохранить более 256 различных значений в переменной byte... это просто не работает. Следуя соглашениям для представления кодовой точки в другом месте (например, в String), лучше всего использовать переменную int.