Какой длины ваша строка?

Добавлено : 29 Dec 2008, 17:32

Какой длины ваша текстовая строка? Вам понадобится ответ на этот вопрос, чтобы проверить допустимые ли данные ввел пользователь в поле данных ограниченной длины. Текстовое поле баз данных обычно ограничивают входные данные определенной длиной, так что вам надо сначала подтвердить длину текста, прежде чем отправить его. Какова бы ни была причина, нам всем иногда необходимо узнать длину текстового поля. Чтобы получить эту информацию, многие программисты используют метод length объекта String. И в большинстве случаев метод length обеспечивает правильный результат. Однако, это не единственный и не всегда верный способ узнать длину объекта String.

По крайней мере у вас есть три общих способа измерить длину текста, если вы используете платформу Java:

  1. количество знаков char в коде
  2. количество символов (characters) или кодовых единиц
  3. число байтов

Подсчет знаков char

В платформе Java используется Unicode Standard для определения символов. Unicode Standard определяет и фиксирует для каждого символа значение, состоящее из 16 битов, в пределе от U+0000 до U+FFFF. Префикс U+ означает допустимое значение в Юникоде как шестнадцатеричное число. В языке Java стандарт фиксированного размера символов удобно преобразуется в тип char. Таким образом значение char может быть представлено любым символом в 16-битном Юникоде.

Большинство программистов знакомы с методом length. Код, приведенный ниже, считает количество знаков char в примере строки. Обратите внимание, что пример объекта String содержит несколько простых символов и несколько символов, определенных в \u нотации языка Java. \u нотация определеяет шестнадцатеричное число и является аналогом нотации U+, используемой Unicode Standard.

private String testString = "abcd\u5B66\uD800\uDF30";
int charCount = testString.length();
System.out.printf
("char count: %d\n", charCount);

Метод length считает количество знаков char в объекте String. Вот что выведет этот код:

char count: 7

Подсчет символов

Когда Unicode версии 4.0 определяет важные новые символы выше U+FFFF, 16-битный тип char не может более представлять все символы. Начиная с Java 2 Platform, Standard Edition 5.0 (J2SE 5.0), платформа Java поддерживает новые символы Юникода - пары 16-битных знаков char, которые называются суррогатными парами (surrogate pair). Два знака char действуют как суррогатное представление символов Юникода в диапазоне от U+10000 до U+10FFFF. Символы в таком новом диапазоне называются дополнительные символы (supplementary characters).

Хотя единичный знак char все еще может представлять значение в Юникоде более U+FFFF, только суррогатная пара из двух char может представлять дополнительные символы. Главное или бóльшее значение в паре лежит в диапазоне от U+D800 до U+DBFF. Следующее или меньшее - от U+DC00 до U+DFFF. Unicode Standard выделил два этих диапазона, чтобы специально использовать в суррогатных парах. Стандарт также определяет алгоритм для преобразования между суррогатными парами и символами, значения которых лежат выше U+FFFF. Используя суррогатные пары, программисты могут представить любой символ в Unicode Standard. Такое специальное использование 16-битных знаков называется UTF-16, и Java Platform пользуется UTF-16 для представления символов в Юникоде. Теперь тип char - это знак в коде UTF-16, необязательно целый символ Юникода (кодовая единица).

Метод length не может считать дополнительные символы, так как он считает только знаки char. К счастью в J2SE 5.0 API есть новый метод String: codePointCount(int beginIndex, int endIndex). Этот метод показывает, сколько единиц Юникода (символов) между двумя индексами. Значения индексов ссылаются на код, обозначающий местоположение знака char. Значение выражения endIndex - beginIndex такое же как и значение, полученное с помощью метода length. Но это не всегда равно значению, возвращаемому методом codePointCount. Если ваш текст содержит суррогатные пары, вычисляемая длина сильно изменится. Суррогатная пара определяет код одного символа, который может состоять из одного или двух знаков char.

Чтобы узнать, сколько символов Юникода в строке, используйте метод codePointCount:

private String testString = "abcd\u5B66\uD800\uDF30";
int charCount = testString.length();
int characterCount = testString.codePointCount(0, charCount);
System.out.printf
("character count: %d\n", characterCount);

Этот пример выведет следующее:

character count: 6

Переменная testString содержит два интересных символа: японский иероглиф, обозначающий "учение", и буква готского алфавита А (GOTHIC LETTER AHSA). Японский иероглиф в Юникоде имеет значение U+5B66 и такой же номер знака char в шестнадцатеричной системе \u5B66. Значение готской буквы - U+10330. В UTF-16 готская буква состоит из суррогатной пары \uD800\uDF30. Пара представляет один целый символ в Юникоде, таким образом число символов в строке равно 6, а не 7.

Подсчет байтов

Сколько байт в строке String? Ответ зависит от использованной кодировки. Одной из наиболее распространенных причин спрашивать "сколько байт?" является желание убедится, что вы удовлетворили ограничением на длину строки в базе данных. Метод getBytes преобразует символы Юникода в байтовую кодировку (в кодировку, работающую не с символами, а байтами) и возвращает количество байт: byte[]. Одной из байтовых кодировок является UTF-8. Это самая распространенная байтовая кодировка, потому что может точно представлять символы Юникода.

Далее представлен код, который преобразует текст в массив байтовых значений:

byte[] utf8 = null;
int byteCount = 0;
try {
 
utf8 = str.getBytes("UTF-8");
  byteCount = utf8.length;
} catch (UnsupportedEncodingException ex) {
 
ex.printStackTrace();
}
System.out.printf("UTF-8 Byte Count: %d\n", byteCount);

Наш набор символов определяет, сколько создано байтов. Кодировка UTF-8 преобразует один символ Юникода в один или несколько (до 4) 8-битовых единиц (байтов). Символы a, b, c и d требуют всего четыре байта. Японский иероглиф превращается в три байта. А готская буква занимает четыре байта. Вот каким будет результат:

UTF-8 Byte Count: 11

String length
Рисунок 1. Строки имеют различную длину, зависящую от того, что вы считаете.

В заключение

Даже используя дополнительные символы, вы никогда не увидите разницу между возвращаемыми значениями метода length и метода codePointCount. Однако, когда вы используете символы выше U+FFFF, вам пригодится умение определять длину различными способами. Если вы будете посылать свои продукты в Японию или Китай, то наверняка попадете в ситуацию, когда методы length и codePointCount вернут различные значения. Базы данных и некоторые форматы публикаций поощряют использование в качестве кодировки UTF-8. Но даже в этом случае измерение длины текста может дать различные результаты. В зависимости от того, как вы будете использовать длину, у вас есть различные способы ее измерить.

Дополнительная информация

Используйте эти ресурсы, чтобы найти информацию по теме данного технического совета:

http://java.sun.com/mailers/techtips/corejava/2006/tt0822.html#1

Теги: string unicode utf8