Может ли действующая строка Unicode содержать FFFF? Является ли Java / CharacterIterator нарушенным?

Вот выдержка из документации java.text.CharacterIterator :

Курсивная часть – это то, что у меня проблемы с пониманием, потому что из моих тестов похоже, что String Java может, безусловно, содержать \uFFFF , и, похоже, с ней не возникает никаких проблем, за исключением, очевидно, предписанного обхода CharacterIterator идиома, которая ломается из-за ложного положительного (например, next() возвращает '\uFFFF' == DONE когда это действительно не сделано).

Вот fragment, иллюстрирующий «проблему» ( см. Также на ideone.com ):

 import java.text.*; public class CharacterIteratorTest { // this is the prescribed traversal idiom from the documentation public static void traverseForward(CharacterIterator iter) { for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) { System.out.print(c); } } public static void main(String[] args) { String s = "abc\uFFFFdef"; System.out.println(s); // abc?def System.out.println(s.indexOf('\uFFFF')); // 3 traverseForward(new StringCharacterIterator(s)); // abc } } 

и так, что здесь происходит?

  • Является ли предписанная обходная идиома «сломанной», потому что она делает неправильное предположение о \uFFFF ?
  • Является ли реализация StringCharacterIterator «сломанной», потому что она, например, не throw \uFFFF IllegalArgumentException если на самом деле \uFFFF запрещен в действительных строках Unicode?
  • Действительно ли верно, что действующие строки Unicode не должны содержать \uFFFF ?
  • Если это правда, значит, Java «сломан» для нарушения спецификации Unicode (для большинства частей), позволяя String содержать \uFFFF ?

EDIT (2013-12-17): Питер О. воспитывает превосходный пункт ниже, что делает этот ответ неправильным. Старый ответ ниже, для исторической точности.


Отвечая на ваши вопросы:

Является ли предписанная обходная идиома «сломанной», потому что она делает неправильное предположение о \ uFFFF?

Нет. U + FFFF является так называемым несимвольным. Из раздела 16.7 стандарта Unicode :

Нехарактерные символы – это коды, которые постоянно сохраняются в стандарте Unicode для внутреннего использования. Они запрещены для использования при открытом обмене текстовыми данными Юникода.

В стандарте Unicode выделяются 66 нехарактерных кодовых точек. Последние два кодовых точки каждой плоскости являются нехарактерами: U + FFFE и U + FFFF на BMP, U + 1FFFE и U + 1FFFF на плоскости 1 и т. Д., До U + 10FFFE и U + 10FFFF на плоскости 16, в общей сложности 34 кодовых пункта. Кроме того, в BMP имеется смежный диапазон еще 32 нехарактерных кодовых точек: U + FDD0..U + FDEF.

Является ли реализация StringCharacterIterator «сломанной», потому что она, например, не выбрасывает исключение IllegalArgumentException, если на самом деле \ uFFFF запрещен в действительных строках Unicode?

Не совсем. Приложениям разрешено использовать эти кодовые точки внутри себя любым способом. Повторное цитирование стандарта:

Приложения могут свободно использовать любые из этих нехарактерных кодовых пунктов внутри, но не должны пытаться их обменивать. Если в открытом обмене получен нехарактер, приложение не требуется для его интерпретации. Однако хорошей практикой является признать ее нехарактерным и предпринять соответствующие действия, например, заменить ее на U + FFFD REPLACEMENT CHARACTER, чтобы указать на проблему в тексте. Не рекомендуется просто удалять нехарактерные коды из такого текста из-за потенциальных проблем безопасности, вызванных удалением неинтерпретируемых символов.

Поэтому, хотя вы никогда не должны сталкиваться с такой строкой от пользователя, другого приложения или файла, вы можете поместить его в строку Java, если вы знаете, что делаете (это в основном означает, что вы не можете использовать CharacterIterator для этой строки, хоть.

Действительно ли верно, что действующие строки Unicode не должны содержать \ uFFFF?

Как указано выше, любая строка, используемая для обмена, не должна содержать их. В вашем приложении вы можете использовать их любым способом.

Конечно, Java- char , являющийся всего лишь 16-разрядным целым без знака, действительно не заботится о ценности, которую он имеет.

Если это правда, значит, Java «сломан» для нарушения спецификации Unicode (для большинства частей), позволяя String содержать \ uFFFF?

Нет. На самом деле раздел о нехарактерах даже предполагает использование U + FFFF в качестве значения дозорного:

В сущности, нехарактеры можно рассматривать как прикладные внутренние частные кодовые точки. В отличие от символов частного использования, описанных в разделе 16.5 «Персонажи частного использования» , которые являются назначенными символами и которые предназначены для использования в открытом обмене, при условии интерпретации по частному соглашению, нехарактеры постоянно сохраняются (не назначаются) и не имеют никакой интерпретации вне внешней их возможного применения – внутреннего частного использования.

U + FFFF и U + 10FFFF. Эти две нехарактерные кодовые точки имеют атрибут связи с наибольшими значениями кодового блока для конкретных форм кодирования Unicode. В UTF-16 U + FFFF ассоциируется с наибольшим значением 16-битного кода, FFFF 16 . U + 10FFFF связан с самым большим юридическим значением 32-битного кода UTF-32, 10FFFF 16 . Этот атрибут делает эти два нехарактерных кодовых пункта полезными для внутренних целей как часовые. Например, они могут использоваться для указания конца списка, для представления значения в индексе, гарантированном выше любого действительного значения символа, и так далее.

CharacterIterator следует за тем, что он возвращает U + FFFF, когда больше символов не доступно. Конечно, это означает, что если у вас есть другое использование для этой точки кода в вашем приложении, вы можете использовать другой несимвольный для этой цели, поскольку U + FFFF уже занят – по крайней мере, если вы используете CharacterIterator.

Некоторые из этих ответов изменились в то же время.

Консорциум Unicode недавно выпустил исправление 9, в котором разъясняется роль нехарактеров, включая U + FFFF, в строках Unicode. В нем указано, что, хотя нехарактеры предназначены для внутреннего использования, они могут встречаться юридически в строках Unicode.

Это означает утверждение «Значение: \ uFFFF, значение« не символ », которое не должно происходить ни в одной из допустимых строк Unicode». теперь неверно, так как U + FFFF может встречаться в действительных строках Unicode.

Соответственно:

  • Является ли «обходная идиома» нарушенной? Да, потому что он делает неправильное предположение о допустимости U + FFFF в строках Unicode.
  • Является ли реализация StringCharacterIterator «сломанной», потому что она не генерирует исключение, если \ uFFFF запрещен в действительных строках Unicode? Поскольку U + FFFF действителен, это здесь не применяется. Но реализация имеет широкую гибкость в сигнализации об ошибке, когда она сталкивается с незаконным текстом по другим причинам, таким как непарные точки суррогатного кода, которые все еще остаются незаконными (см. Раздел соответствия C10 в главе 3 стандарта Unicode).
  • Верно ли, что допустимые строки Unicode не должны содержать \ uFFFF? U + FFFF не является незаконным в действительной строке Unicode. Однако U + FFFF зарезервирован как нехарактерный, и, как правило, в значимом тексте не возникает. Исправление удалило текст, в котором несимволы «никогда не должны меняться», что, по словам Corrigendum, происходит «в любое время, когда строка Unicode пересекает границу API», включая здесь описанный здесь API StringCharacterIterator.
  • Если это правда, то является ли «сломан» Java нарушением спецификации Unicode, позволяя String содержать \ uFFFF? Спецификация для java.lang.String говорит: «Строка представляет строку в формате UTF-16». U + FFFF является законным в строке Unicode, поэтому Java не нарушает Unicode для разрешения U + FFFF в строке, содержащей его.

Является ли реализация StringCharacterIterator «сломанной», потому что она, например, не выбрасывает исключение IllegalArgumentException, если на самом деле \ uFFFF запрещен в действительных строках Unicode?

Не строго согласно Unicode, но он несовместим с остальными интерфейсами обработки строк Java, и эта несогласованность может иметь очень неприятные эффекты. Подумайте о всех дырах в безопасности, которые мы получили от строковой обработки, которая делает vs. не обрабатывает \0 как терминатор.

Я бы сильно избегал интерфейса CharacterIterator .

Да, использование CharacterIterator 0xFFFF в качестве значения DONE является немного аномальным. Но все это имеет смысл с точки зрения эффективной обработки текста.

Класс String не запрещает 0xFFFF «несимвольные» и другие зарезервированные или неотображаемые коды Unicode. Для этого потребуется, чтобы конструкторы String проверяли каждое заданное значение char . Это также будет представлять проблемы с обработкой текста, содержащего кодовые точки Юникода, определенные в будущем (в отношении JVM) версии Unicode.

С другой стороны, интерфейс CharacterIterator предназначен для обеспечения итерации путем вызова одного только метода; т.е. next() . Они решили использовать выделенное значение char чтобы указать «не больше», потому что другие альтернативы:

  • бросая исключение (что слишком дорого) или
  • используя int как возвращаемый тип, жизнь которого более сложна для вызывающего.

Если CharacterIterator используется для «реального» текста Unicode, то тот факт, что вы не можете включить 0xFFFF, не является проблемой. Действительный текст Юникода не содержит эту кодовую точку. (Фактически, причина, по которой 0xFFFF зарезервирована как несимвольный, заключается в поддержке приложений, где текст Юникода представлен в виде строк, заканчивающихся несимвольным значением. Использование 0xFFFF в качестве символа полностью нарушило бы.)

Нижняя строка:

  • если вы хотите строгие строки Unicode, тогда не используйте String и
  • если вы хотите перебирать строки Java, содержащие значения 0xFFFF, тогда не используйте CharacterIterator.
  • Как интернационализировать веб-приложение Java?
  • iconv: Преобразование из Windows ANSI в UTF-8 с помощью спецификации
  • В чем разница между _tmain () и main () в C ++?
  • Выход файла UTF-8 в R
  • Действительные символы в имени classа Java
  • Моя Windows 7 неожиданно перестала отображать символы Unicode
  • Как преобразовать wstring в строку?
  • Кодировка Java Unicode
  • std :: wstring VS std :: string
  • Невозможно получить чешских персонажей при создании PDF-файла
  • Как распознать, содержит ли строка символы unicode?
  • Давайте будем гением компьютера.