Может ли действующая строка Unicode содержать FFFF? Является ли Java / CharacterIterator нарушенным?
Вот выдержка из документации java.text.CharacterIterator
:
Этот
interface
определяет протокол для двунаправленной итерации по тексту. Итератор выполняет итерацию по ограниченной последовательности символов. […] Методыprevious()
иnext()
используются для итерации. Они возвращаютDONE
если […], сигнализируя, что iterator достиг конца последовательности.
static final char DONE
: Константа, которая возвращается, когда iterator достиг конца или начала текста. Значение –\uFFFF
, значение «не символ», которое не должно происходить ни в одной из допустимых строк Unicode .
- WChars, кодировки, стандарты и переносимость
- Каков правильный способ кодирования URL-символов Unicode?
- Чтение электронной почты с использованием Pop3 в C #
- Детерминированный способ найти, какие установленные шрифты поддерживают данный символ или скрипт Unicode?
- В чем разница между utf8_general_ci и utf8_unicode_ci
Курсивная часть – это то, что у меня проблемы с пониманием, потому что из моих тестов похоже, что 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
?
- Почему Firefox не отображает некоторые символы?
- Почему в Firefox видны только некоторые символы Юникода?
- Как отключить Unicode в проекте VC ++?
- Преобразование между строкой, u16string и u32string
- Действительно хорошие, плохие примеры тестовых данных UTF-8
- Печать строк UTF-8 с помощью printf-wide или многобайтовых строковых литералов
- UTF-8, UTF-16 и UTF-32
- Что предоставляет `` и где он документирован?
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.