X

char with codePoint

Сегодня я хотел бы разобраться с двумя разными наборами методов для работы с символами: char* и codePoint*

Давайте сразу перейдем к делу и потестим такой вот пример:

public class Main {
 public static void main(String[] args) {

  String str = "A" + "\uD835\uDD0A"+ "B" + "C";

  System.out.print(str);
  System.out.print(" - length: "+str.length());
  System.out.print(" - codePointCount: "+str.codePointCount(0, str.length()));

 }
}

Результат:

A@BC - length: 5 - codePointCount: 4

@=вместо собачки будет закрученный символ

Как же так получилось, что length нам говорит, что в нашей строке 5 символов, хотя мы видим только 4? Все дело в том, что length считает именно символы, и если хорошо присмотреться к созданию строки, то мы как раз и увидим что между A и B находятся два символа - \uD835 и \uDD0A. Тогда почему, мы видим только четыре, а не пять? Дело в том, что совокупность этих двух символов представляет символ из кодировки UTF-16. Вот такое есть объяснение:

UTF-8
Текст, состоящий только из символов с номером меньше 128, при записи в UTF-8 превращается в обычный текст ASCII. И наоборот, в тексте UTF-8 любой байт со значением меньше 128 изображает символ ASCII с тем же кодом. Остальные символы Юникода изображаются последовательностями длиной от 2 до 6 байтов (реально только до 4 байт, поскольку использование кодов больше 221 не планируется), в которых первый байт всегда имеет вид 11xxxxxx, а остальные — 10xxxxxx.Проще говоря, в формате UTF-8 символы латинского алфавита, знаки препинания и управляющие символы ASCII записываются кодами US-ASCII, a все остальные символы кодируются при помощи нескольких октетов со старшим битом 1. Это приводит к двум эффектам.

 

UTF-16
UTF-16 (англ. Unicode Transformation Format) в информатике — один из способов кодирования символов из Unicode в виде последовательности 16-битных «байтов». Символы с кодами меньше 0x10000 (216) представляются как есть, а символы с кодами 0x10000–0x10FFFE — в виде последовательности двух 16-битных «байтов», первый из которых лежит в диапазоне 0xD800–0xDBFF, а второй — 0xDC00–0xDFFF. Легко видеть, что имеется как раз 210 * 210 = 220 таких комбинаций
Следует отметить, что по стандарту никакие символы не могут иметь коды собственно из диапазона 0xD800–0xDFFF, так что расшифровка кодировки всегда однозначна. Впрочем, в подавляющем большинстве случаев текст в UTF-16 является просто последовательностью символов из UCS-2 (BMP), т.к. символы Unicode после кода 0x10000 используются крайне редко.

Что же такое codePoint (кодовая точка)?

Представьте, что есть символы, а есть буквы. Так вот буквы могут состоять из 2-х символов, например я представляю себе букву Й как И(символ) + ~ (символ).

На самом деле Й не из UTF-16, а из ASCII, этот пример только для того, чтобы вы поняли, что имеется ввиду под codePoint

Точно так же и символы из UTF-16 могут состоять из двух символов. Соответственно для работы с ними нужно использовать методы работающие с codePoint

Более подробнее про CodePoint читайте тут: Кодовые точки Unicode и русские символы в исходных кодах и программах Java. JDK 1.6

Как работает codePoint для не UTF-16 символов?

Как и ожидается, точно так же как и length:

 

public class Main {
 public static void main(String[] args) {

  String str = "안녕하세요 세계"; // Hello world на корейском

  System.out.print(str);
  System.out.print(" - length: "+str.length());
  System.out.print(" - codePointCount: "+str.codePointCount(0, str.length()));

 }
}

Результат:

안녕하세요 세계 - length: 8 - codePointCount: 8

Что же использовать?

Если Вы уверены, что Ваша программа никогда не будет работать с символами в UTF-16 - используйте, обычные методы для работы с char. Но если есть хоть малейший шанс появления UTF-16 символов используйте codePoint. Представьте себе такую ситуацию, ваша программа обрабатывает 10000 текстов каждый день, но в 3% случаях, дает непредвиденные результаты или еще хуже сбои. Вы просто недоумеваете в чем причина, и в случае если не знаете про особенности работы с UTF-16, вы будете очень долго искать баг. Поэтому сразу думайте, как лучше поступить в вашем случае.

Вопросы для собеседования:

  1. В чем отличие charAt(0) и codePointAt(0)?
  2. Что такое "кодовая точка"?
  3. Приведите пример программы показывающий различия работы с символами и "кодовыми точками".

Ответы:

  1. Метод charAt(0) - возвратит первый символ строки. Метод codePointAt(0) - возвратит первую букву (кодовую точку) указанной строки.
  2. Кодовая точка - это символ unicode, представленный последовательностью одним или несколькими символами. Можно сказать что это буква, которая может состоять из нескольких символов.
  3. См. первый пример кода в этом посте.

 

 

Категории: Java Java labs