Подтвердить что ты не робот

Сравнение char с кодовой точкой?

Каков "правильный" способ сравнения кодовой точки с символом Java? Например:

int codepoint = String.codePointAt(0);
char token = '\n';

Я знаю, что, вероятно, могу:

if (codepoint==(int) token)
{ ... }

но этот код выглядит хрупким. Существует ли формальный метод API для сравнения codepoints - chars или преобразования char до codepoint для сравнения?

4b9b3361

Ответ 1

Немного фона: Когда Java появилась в 1995 году, тип char был основан на исходной спецификации Unicode 88, который был ограничен 16 бит. Год спустя, когда Unicode 2.0 был реализован, понятие суррогатных символов было введено, чтобы выйти за пределы 16 бит.

Java внутренне представляет все String в формате UTF-16. Для кодовых точек, превышающих U + FFFF, кодовая точка представлена ​​суррогатной парой, т.е. Двумя char, первая из которых является узлом с высоким суррогатным кодом (в диапазоне \uD800-\uDBFF), вторая - низкая -surrogate code unit (в диапазоне \uDC00-\uDFFF).

С первых дней все базовые методы Character были основаны на предположении, что кодовая точка может быть представлена ​​в одном char, так что будут выглядеть сигнатуры метода. Я думаю, чтобы сохранить обратную совместимость, которая не была изменена при появлении Unicode 2.0, и при работе с ними необходимо проявлять осторожность. Чтобы привести цитату из документации Java:

  • Методы, принимающие только значение char, не могут поддерживать дополнительные символы. Они обрабатывают значения char из суррогатных диапазонов как символы undefined. Например, Character.isLetter('\ uD840') возвращает false, хотя это конкретное значение, если следовать за любым значением с низким суррогатом в строке, будет представлять букву.
  • Методы, принимающие значение int, поддерживают все символы Юникода, включая дополнительные символы. Например, Character.isLetter(0x2F81A) возвращает true, потому что значение кодовой точки представляет собой букву (идеолог CJK).

Приведение char в int, как и в вашем примере, отлично работает.

Ответ 2

Класс Character содержит много полезных методов работы с кодовыми точками Unicode. Обратите внимание на методы, такие как Character.toChars(int), которые возвращают массив символов. Если ваш код находится в дополнительном диапазоне, то массив будет содержать два символа.

How you want to compare the values depends on whether you want to support the full range of Unicode values. This sample code can be used to iterate through a String codepoints, testing to see if there is a match for the supplementary character MATHEMATICAL_FRAKTUR_CAPITAL_G (𝔊 - U+1D50A):

public final class CodePointIterator {

  private final String sequence;
  private int index = 0;

  public CodePointIterator(String sequence) {
    this.sequence = sequence;
  }

  public boolean hasNext() {
    return index < sequence.length();
  }

  public int next() {
    int codePoint = sequence.codePointAt(index);
    index += Character.charCount(codePoint);
    return codePoint;
  }

  public static void main(String[] args) {
    String sample = "A" + "\uD835\uDD0A" + "B" + "C";
    int match = 0x1D50A;
    CodePointIterator pointIterator = new CodePointIterator(sample);
    while (pointIterator.hasNext()) {
      System.out.println(match == pointIterator.next());
    }
  }
}

Для Java 8 и далее CharSequence.codePoints() можно использовать:

public static void main(String[] args) {
  String sample = "A" + "\uD835\uDD0A" + "B" + "C";
  int match = 0x1D50A;
  sample.codePoints()
        .forEach(cp -> System.out.println(cp == match));
}

Я создал таблицу чтобы помочь получить дескриптор длины строки Unicode и случаев сравнения, которые иногда нужно обрабатывать.

Ответ 3

Для символа, который может быть представлен одним char (16 бит, базовая многоязычная плоскость), вы можете получить кодовое слово просто, выставив char в целое число (как подсказывает вопрос), так что нет требуется специальный метод для выполнения преобразования.

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

Ответ 4

Для символов в базовой многоязычной плоскости, приведение char в int приведет к вам код. Это соответствует всем значениям unicode, которые могут быть закодированы в одном 16-битном значении char. Значения вне этой плоскости (с кодовыми точками, превышающими 0xffff) не могут быть выражены как один символ. Вероятно, поэтому нет значения Character.toCodePoint(char).

Ответ 5

Java использует 16-битную (UTF-16) модель для обработки символов, поэтому любые символы с кодовыми точками > 0xFFFF хранятся в строках как пары 16-разрядных символов, используя два surrogate для отображения плоскости и символа в плоскости.

Если вы хотите правильно обрабатывать символы и строки в соответствии со стандартом Unicode, вам необходимо обработать строки, учитывая это.

XML много заботится об этом; полезно получить доступ к классу XMLChar в Xerces (который поставляется с Java версии 5.0 и выше) для кода, связанного с символами.

Также поучительно посмотреть на Saxon процессор XSLT/XQuery, поскольку он является хорошо зарекомендовавшим себя XML-приложением, он должен учитывайте, как Java хранит кодовые точки в строках. XQuery 1.0 и XPath 2.0 имеют функции для codepoints-to-string и string-to-codepoints; может быть поучительно получить копию саксонской игры и сыграть с ними, чтобы посмотреть, как они работают.