Метод jlength возвращает число кодовых позиций в строке, а не байтов. Если нужно получить число байтов, пользуйтесь методом length.

$KCODE = 'u'

require 'jcode'

sword = 'épée'

sword.jlength # 4

sword.length  # 6

Такие методы, как upcase и capitalize, обычно неправильно работают со специальными символами. Это ограничение текущей версии Ruby. (Не стоит считать ошибкой, поскольку получить представление слова с первой прописной буквой довольно трудно; такая задача просто не решается в схеме интернационализации Ruby. Считайте, что это нереализованное поведение.)

$KCODE = 'u'

sword.upcase     # 'ÉPÉE'

sword.capitalize # 'épée'

Если вы не пользуетесь монолитной формой, то в некоторых случаях метод может сработать, поскольку латинские буквы отделены от диакритических знаков. Но в общем случае работать не будет — в частности, для турецкого, немецкого, голландского и любого другого языка с нестандартными правилами преобразования регистра.

Возможно, вы думаете, что неакцентированные символы в некотором смысле эквивалентны своим акцентированным вариантам. Это почти всегда не так. Здесь мы имеем дело с разными символами. Убедимся в этом на примере метода count:

$KCODE = 'u'

sword.count('e') # 1 (не 3)

Но для составных (не монолитных) символов верно прямо противоположное. В этом случае латинская буква распознается.

Метод count возвращает сбивающий с толку результат, когда ему передается многобайтовый символ. Метод jcount ведет себя в этом случае правильно:

$KCODE = 'u'

sword.count('eé')  # 5 (не 3)

sword.jcount('eé') # 3

Существует вспомогательный метод mbchar?, который определяет, есть ли в строке многобайтовые символы.

$KCODE = 'u'

sword.mbchar? # 0 (смещение первого многобайтового символа)

'foo'.mbchar? # nil

В библиотеке jcode переопределены также методы chop, delete, squeeze, succ, tr и tr_s. Применяя их в режиме UTF-8, помните, что вы работаете с версиями, «знающими о многобайтовости». При попытке манипулировать многобайтовыми строками без библиотеки jcode вы можете получить странные или ошибочные результаты.

Можно побайтно просматривать строку, как обычно, с помощью итератора each_byte. А можно просматривать посимвольно с помощью итератора each_char. Второй способ имеет дело с односимвольными строками, первый (в текущей версии Ruby) — с однобайтными целыми. Разумеется, мы в очередной раз приравниваем кодовую позицию к символу. Несмотря на название, метод each_char на самом деле перебирает кодовые позиции, а не символы.

$KCODE = 'u'

sword.each_byte {|x| puts x } # Шесть строк с целыми числами.

sword.each_char {|x| puts x } # Четыре строки со строками.

Если вы запутались, не переживайте. Все мы через это проходили. Я попытался свести все вышесказанное в таблицу 4.1.

Таблица 4.1. Составные и монолитные формы

Монолитная форма 'é'
Название символа Глиф Кодовая позиция Байты UTF-8 Примечания
Строчная латинская e с акутом é U+00E9 0xC3 0хА9 Один символ, одна кодовая позиция, один байт
Составная форма 'é'
Название символа Глиф Кодовая позиция Байты UTF-8 Примечания
Строчная латинская е е U+0065 0x65 Один символ, две кодовых позиции (два «программистских символа»), три байта UTF-8
Модифицирующий акут ́ U+0301 0xCC 0x81

Что еще надо учитывать при работе с интернациональными строками? Квадратные скобки по- прежнему относятся к байтам, а не к символам. Но при желании это можно изменить. Ниже приведена одна из возможных реализаций (не особенно эффективная, зато понятная):

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату