Факты и терминология
Как вы, наверное, знаете, Java использует UTF-16 для представления строк . Чтобы понять путаницу с String.length () , вы должны быть знакомы с некоторыми терминами Encoding / Unicode.
Кодовая точка: уникальное целочисленное значение, представляющее символ в кодовом пространстве.
Кодовая единица: битовая последовательность, используемая для кодирования символов (кодовые точки). Для представления кодовой точки может потребоваться одна или несколько единиц кода.
UTF-16
Кодовые точки Unicode логически разделены на 17 плоскостей. Первая плоскость, Базовая многоязычная плоскость (BMP), содержит «классические» символы (от U + 0000 до U + FFFF). Другие плоскости содержат дополнительные символы (от U + 10000 до U + 10FFFF).
Символы (кодовые точки) из первой плоскости кодируются в одну 16-битную кодовую единицу с одинаковым значением. Дополнительные символы (кодовые точки) кодируются в двух кодовых единицах (для конкретных кодировок, пояснение см. В Wiki ).
пример
Символ:
кодовая точка Unicode: U + 0041
UTF-16 кодовых единиц: 0041
Символ: Математическая двойная
буква A Кодовая точка Unicode: U + 1D538 Кодовые единицы
UTF-16: D835 DD38
Как вы можете видеть здесь, есть символы, которые закодированы в двух единицах кода.
String.length ()
Давайте посмотрим на Javadoc метода length () :
public int length() Returns the length of this string. The length is equal to the number of Unicode code units in the string.
Поэтому, если у вас есть один дополнительный символ, который состоит из двух кодовых единиц, длина этого одного символа равна двум .
// Mathematical double-struck capital A String str = "\uD835\uDD38"; System.out.println(str); System.out.println(str.length()); //prints 2
Что правильно в соответствии с документацией, но, возможно, это не ожидается.
~ Решение
Вам нужно посчитать кодовые точки, а не кодовые единицы:
String str = "\uD835\uDD38"; System.out.println(str); System.out.println(str.codePointCount(0, str.length()));
Смотрите: codePointCount (int beginIndex, int endIndex)