char with codePoint
Сегодня я хотел бы разобраться с двумя разными наборами методов для работы с символами: char* и codePoint*
Давайте сразу перейдем к делу и потестим такой вот пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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())); } } |
Результат:
1 2 3 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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())); } } |
Результат:
1 2 3 |
안녕하세요 세계 - length: 8 - codePointCount: 8 |
Что же использовать?
Если Вы уверены, что Ваша программа никогда не будет работать с символами в UTF-16 - используйте, обычные методы для работы с char. Но если есть хоть малейший шанс появления UTF-16 символов используйте codePoint. Представьте себе такую ситуацию, ваша программа обрабатывает 10000 текстов каждый день, но в 3% случаях, дает непредвиденные результаты или еще хуже сбои. Вы просто недоумеваете в чем причина, и в случае если не знаете про особенности работы с UTF-16, вы будете очень долго искать баг. Поэтому сразу думайте, как лучше поступить в вашем случае.
Вопросы для собеседования:
- В чем отличие charAt(0) и codePointAt(0)?
- Что такое "кодовая точка"?
- Приведите пример программы показывающий различия работы с символами и "кодовыми точками".
Ответы:
- Метод charAt(0) - возвратит первый символ строки. Метод codePointAt(0) - возвратит первую букву (кодовую точку) указанной строки.
- Кодовая точка - это символ unicode, представленный последовательностью одним или несколькими символами. Можно сказать что это буква, которая может состоять из нескольких символов.
- См. первый пример кода в этом посте.
Author: | Tags: /
| Rating:
Leave a Reply