В языке Java строки реализованы как последовательности значений типа char. Тип char позволяет задавать кодовые единицы, представляющие кодовые точки Unicode в кодировке UTF-16. Наиболее часто используемые символы Unicode представляются одной кодовой единицей. Дополнительные символы задаются парами кодовых единиц.
Метод length() возвращает количество кодовых единиц для данной строки в кодировке UTF-16. Ниже приведен пример использования данного метода:
1 2 |
String greeting = "Hello"; int n = greeting.length(); // Значение n равно 5. |
Чтобы определить реальную длину, представляющую собой число кодовых точек, надо использовать следующий вызов:
1 |
int cpCount = greeting.codePointCount(0, greeting.length()); |
Метод s.charAt(n) возвращает кодовую единицу в позиции n, где n находится в интервале от 0 до s.length() — 1. Ниже приведены примеры вызова данного метода.
1 |
char first = greeting.charAt(0); // первый символ - 'H'char last = greeting.charAt(4); // последний символ - 'o' |
Для получения i-й кодовой точки надо использовать приведенные ниже выражения.
1 2 |
int index = greeting.offsetByCodePoints(0, i); int cp = greeting.codePointAt(index); |
Java подсчитывает кодовые единицы в строках специфическим образом: первая кодовая единица в строке расположена в позиции 0. Это соглашение пришло из языка C, где по техническим причинами подсчет позиций начинается с 0. Эта причина давно ушла в прошлое, а неудобство осталось. Однако этому соглашению следует настолько много программистов, что проектировщики Java решили сохранить его.
Зачем мы подняли шум относительно кодовых единиц? Рассмотрим приведенную ниже строку:
1 |
Z is the set of integers |
Для представления символа Z используются две кодовые единицы UTF-16. Приведенный ниже вызов метода даст не код пробела, а второй код символа Z. Чтобы избежать возникновения данной проблемы, не следует применять тип char, так как он представляет символы на слишком низком уровне.
Если вы хотите просмотреть строку посимвольно, то есть получить по очереди каждую кодовую точку, вам надо использовать фрагмент кода, подобный показанному ниже.
1 2 3 |
int cp = sentence.codePointAt(i); if(Character.isSupplementaryCodePoint(cp)) i+=2; eslt i++; |
К счастью, метод codePointAt() определяет, является ли кодовая единица первой или второй частью дополнительного символа, и всегда возвращает корректный результат. Поэтому вы можете организовать просмотр строки и в обратном направлении.
1 2 3 |
i--; int cp = sentence.codePointAt(i); if(Character.isSupplementaryCodePoint(cp)) i--; |