Вопрос-ответ

What is a "surrogate pair" in Java?

Что такое "суррогатная пара" в Java?

Я читал документацию по StringBuffer, в частности по методу reverse(). В этой документации что-то упоминается о суррогатных парах. Что такое суррогатная пара в данном контексте? И что такое суррогаты low и high?

Переведено автоматически
Ответ 1

Термин "суррогатная пара" относится к средству кодирования символов Unicode с высокими кодовыми точками в схеме кодирования UTF-16.

В кодировке символов Unicode символы сопоставляются со значениями от 0x0 до 0x10FFFF.

Внутренне Java использует схему кодирования UTF-16 для хранения строк текста в Юникоде. В UTF-16 используются 16-битные (двухбайтовые) единицы кода. Поскольку 16 бит могут содержать только диапазон символов от 0x0 до 0xFFFF, некоторая дополнительная сложность используется для хранения значений выше этого диапазона (от 0x10000 до 0x10FFFF). Это делается с использованием пар единиц кода, известных как суррогаты.

Суррогатные кодовые единицы находятся в двух диапазонах, известных как "высокие суррогаты" и "низкие суррогаты", в зависимости от того, разрешены ли они в начале или в конце последовательности из двух кодовых единиц.

Ответ 2

Ранние версии Java представляли символы Unicode с использованием 16-разрядного типа данных char. В то время такая конструкция имела смысл, поскольку все символы Unicode имели значения меньше 65 535 (0xFFFF) и могли быть представлены в 16 битах. Однако позже Unicode увеличил максимальное значение до 1,114,111 (0x10FFFF). Поскольку 16-разрядные значения были слишком малы для представления всех символов Unicode в Unicode версии 3.1, 32-разрядные значения, называемые кодовыми точками, были приняты для схемы кодирования UTF-32. Но 16-битные значения предпочтительнее 32-битных для эффективного использования памяти, поэтому Unicode представила новый дизайн, позволяющий продолжать использовать 16-битные значения. Эта конструкция, принятая в схеме кодирования UTF-16, присваивает 1024 значения 16-битным старшим суррогатам (в диапазоне от U+ D800 до U+DBFF) и еще 1024 значения 16-битным младшим суррогатам (в диапазоне от U+ DC00 до U+ DFFF). Он использует высокий суррогат , за которым следует низкий суррогат — суррогатная пара — для представления (произведения 1,024 и 1,024) 1,048,576 (0x100000) значений между 65,536 (0x10000) и 1,114,111 (0x10FFFF) .

Ответ 3

Добавляем еще немного информации к приведенным выше ответам из этого поста.

Протестировано в Java-12, должно работать во всех версиях Java выше 5.

Как упоминалось здесь: https://javalang.ru/a/47505451/2987755,
какой бы символ (чей Unicode стоит выше U + FFFF) ни был представлен как суррогатная пара, которую Java хранит как пару значений char , т. Е. Один символ Unicode представлен как два соседних символа Java.
Как мы можем видеть в следующем примере.


  1. Длина:


    "🌉".length()  //2, Expectations was it should return 1

    "🌉".codePointCount(0,"🌉".length()) //1, To get the number of Unicode characters in a Java String


  2. Равенство:

    Введите "🌉" в строку, используя Unicode \ud83c\udf09, как показано ниже, и проверьте равенство.


    "🌉".equals("\ud83c\udf09") // true

    ​Java не поддерживает UTF-32


    "🌉".equals("\u1F309") // false


  3. Вы можете преобразовать символ Unicode в строку Java


    "🌉".equals(new String(Character.toChars(0x0001F309))) //true


  4. String.substring() не учитывает дополнительные символы


    "🌉🌐".substring(0,1) //"?"
    "🌉🌐".substring(0,2) //"🌉"
    "🌉🌐".substring(0,4) //"🌉🌐"

    Чтобы решить эту проблему, мы можем использовать String.offsetByCodePoints(int index, int codePointOffset)


    "🌉🌐".substring(0,"🌉🌐".offsetByCodePoints(0,1) // "🌉"
    "🌉🌐".substring(2,"🌉🌐".offsetByCodePoints(1,2)) // "🌐"


  5. Повторение строки Unicode с помощью BreakIterator



  6. Сортировка строк с помощью Unicode java.text.Средство сортировки



  7. Символьные методы toUpperCase(), toLowerCase(), не должны использоваться, вместо этого используйте строковые заглавные и строчные буквы определенной локали.



  8. Character.isLetter(char ch) не поддерживается, лучше использовать Character.isLetter(int codePoint), для каждого methodName(char ch) метода в классе Character будет тип of methodName(int codePoint) который может обрабатывать дополнительные символы.



  9. Укажите кодировку в String.getBytes(), преобразуя байты в строку, InputStreamReader, OutputStreamWriter



  10. В Java-21 добавлены новые методы, java.lang.Character.isEmoji и новые шаблоны, связанные с регулярными выражениями, данные emoji из здесь, эти новые функции могут быть полезны, если вы используете любую библиотеку, упомянутую здесь


    public static void main(String[] args) {
    System.out.println('☺' + " isEmoji : " + isEmoji('☺')); // true
    System.out.println('❌' + " isEmoji : " + isEmoji('❌')); // true
    System.out.println('ž' + " isEmoji : " + isEmoji('ž')); // false

    emojiChecks("A");
    emojiChecks("©");
    emojiChecks("☺");
    emojiChecks("\uD83D\uDE0A");
    }

    private static void emojiChecks(String emoji) {
    // If any string is not emoji then it can not be moji_Component, Emoji_Presentation, Emoji_Modifier, and Emoji_Modifier_Base.
    // Ref: https://unicode.org/reports/tr51/#Emoji_Properties_and_Data_Files
    final Pattern emojiPattern = Pattern.compile("\\p{IsEmoji}");
    final Pattern emojiModifierBasePattern = Pattern.compile("\\p{IsEmoji_Modifier_Base}");
    final Pattern emojiComponentPattern = Pattern.compile("\\p{IsEmoji_Component}");
    final Pattern emojiPresentationPattern = Pattern.compile("\\p{IsEmoji_Presentation}");
    final Pattern isExtendedPictographicPattern = Pattern.compile("\\p{IsExtended_Pictographic}");
    System.out.println(emoji + " IsEmoji: " + emojiPattern.matcher(emoji).matches());
    System.out.println(emoji + " IsEmojiModifierBase: " + emojiModifierBasePattern.matcher(emoji).matches());
    System.out.println(emoji + " IsEmojiComponent: " + emojiComponentPattern.matcher(emoji).matches());
    System.out.println(emoji + " IsEmojiPresentation: " + emojiPresentationPattern.matcher(emoji).matches());
    System.out.println(emoji + " IsExtended_Pictographic: " + isExtendedPictographicPattern.matcher(emoji).matches());
    System.out.println("----------------------------------------");
    }

    // output
    ☺ isEmoji : true
    ❌ isEmoji : true
    ž isEmoji : false
    A IsEmoji: false
    A IsEmojiModifierBase: false
    A IsEmojiComponent: false
    A IsEmojiPresentation: false
    A IsExtended_Pictographic: false
    ----------------------------------------
    © IsEmoji: true
    © IsEmojiModifierBase: false
    © IsEmojiComponent: false
    © IsEmojiPresentation: false
    © IsExtended_Pictographic: true
    ----------------------------------------
    ☺ IsEmoji: true
    ☺ IsEmojiModifierBase: false
    ☺ IsEmojiComponent: false
    ☺ IsEmojiPresentation: false
    ☺ IsExtended_Pictographic: true
    ----------------------------------------
    😊 IsEmoji: true
    😊 IsEmojiModifierBase: false
    😊 IsEmojiComponent: false
    😊 IsEmojiPresentation: true
    😊 IsExtended_Pictographic: true
    ----------------------------------------



Ссылка:

https://coolsymbol.com/emojis/emoji-for-copy-and-paste.html#objects

https://www.online-toolz.com/tools/text-unicode-entities-convertor.php

https://www.ibm.com/developerworks/library/j-unicode/index.html

https://www.oracle.com/technetwork/articles/javaee/supplementary-142654.html

Подробнее о примере image1 image2
Другие термины, которые стоит изучить: Нормализация, BiDi

Ответ 4

В этой документации говорится о том, что недопустимые строки UTF-16 могут стать допустимыми после вызова reverse метода, поскольку они могут быть заменой допустимых строк. Суррогатная пара (обсуждается здесь) представляет собой пару 16-битных значений в UTF-16, которые кодируют одну кодовую точку Unicode; низкие и высокие значения - это две половины этой кодировки.

2024-02-29 17:56 java