Может ли допустимая строка Unicode содержать FFFF?Java / CharacterIterator не работает? - PullRequest
23 голосов
/ 14 августа 2010

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

  • Этот interface определяет протокол для двунаправленной итерации по тексту. Итератор перебирает ограниченную последовательность символов. [...] Методы previous() и next() используются для итерации. Они возвращают DONE if [...], сигнализируя, что итератор достиг конца последовательности.

  • static final char DONE: Константа, которая возвращается, когда итератор достигает либо конца, либо начала текста. Значение \uFFFF, значение "не символ" , которое не должно встречаться ни в одной допустимой строке Unicode .

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

Вот фрагмент для иллюстрации «проблемы» ( см. Также на 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 и IllegalArgumentException, если на самом деле \uFFFF запрещено в допустимых строках Unicode?
  • Правда ли, что допустимые строки Unicode не должны содержать \uFFFF?
  • Если это правда, то Java "сломан" из-за нарушения спецификации Unicode из-за (в большинстве случаев) разрешения String содержать \uFFFF в любом случае?

Ответы [ 4 ]

27 голосов
/ 14 августа 2010

РЕДАКТИРОВАТЬ (2013-12-17): Питер О. поднимает отличную точку ниже, что делает этот ответ неверным.Старый ответ ниже, для исторической точности.


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

Не нарушена ли предписанная идиома обхода, потому что она делает неверное предположение о \ uFFFF?

Нет.U + FFFF - это так называемый не-символ.С Раздел 16.7 Стандарта Юникода :

Нехарактеры - это кодовые точки, которые постоянно зарезервированы в Стандарте Юникода для внутреннего использования.Они запрещены для использования в открытом обмене текстовыми данными 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 "не работает""за нарушение спецификации Юникода из-за того, что (в большинстве случаев) позволяет String содержать \ uFFFF в любом случае?

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

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

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

18 голосов
/ 18 мая 2013

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

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

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

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

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

Не нарушена ли реализация StringCharacterIterator, потому что она, например, не генерирует исключение IllegalArgumentException, если на самом деле \ uFFFF запрещено в допустимых строках Unicode?

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

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

2 голосов
/ 14 августа 2010

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

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

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

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

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

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

  • если вам нужны строгие строки Unicode, не используйте String и
  • Если вы хотите перебрать строки Java, содержащие значения 0xFFFF, не используйте CharacterIterator.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...