Может ли допустимая строка Unicode содержать FFFF? Java / CharacterIterator не работает?

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

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

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

Курсивом является то, что у меня возникают проблемы с пониманием, потому что из моих тестов, выбросить и IllegalArgumentException , если фактически \ uFFFF запрещено в допустимых строках Unicode?

  • Действительно ли действительно, что действительные строки Unicode не должны содержать \ uFFFF ?
  • Если это правда, то Java «сломан» за нарушение спецификации Unicode, поскольку позволяет String содержать \ uFFFF в любом случае ?
  • 24
    задан Peter O. 21 August 2014 в 02:36
    поделиться

    3 ответа

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


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

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

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

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

    ...

    В стандарте Юникод зарезервировано 66 несимвольных кодовых точек. Последние две кодовые точки каждой плоскости являются несимвольными: U+FFFE и U+FFFF на BMP, U+1FFFE и U+1FFFF на плоскости 1, и так далее, вплоть до U+10FFFE и U+10FFFF на плоскости 16, всего 34 кодовые точки. точек. Кроме того, существует непрерывный диапазон из еще 32 несимвольных кодовых точек в BMP: 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. Эти две несимвольные кодовые точки имеют свойство связаны с наибольшими значениями кодовых единиц для определенных форм кодирования Юникод. В UTF-16, U+FFFF ассоциируется с наибольшим 16-битным значением кодовой единицы, FFFF16. U+10FFFF ассоциируется с наибольшим легальным значением 32-битной кодовой единицы UTF-32, 10FFFF16. Этот атрибут делает эти две несимвольные кодовые точки полезными для внутренних целей в качестве дозорных. Например, например, они могут использоваться для обозначения конца списка, для представления значения в индексе гарантированно выше любого допустимого символьного значения, и так далее.

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

    27
    ответ дан 28 November 2019 в 23:10
    поделиться

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

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

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

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

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

    Итог:

    • если вам нужны строгие строки Unicode, не используйте String и
    • , если вы хотите перебирать строки Java, содержащие значения 0xFFFF, тогда не используйте CharacterIterator.
    2
    ответ дан 28 November 2019 в 23:10
    поделиться

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

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

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

    3
    ответ дан 28 November 2019 в 23:10
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: