Затем создадим хэшированную таблицу, чтобы установить соответствие между исходными и трансформированными строками, и воспользуемся ей для сортировки исходных строк. Наличие такой таблицы позволяет провести трансформацию только один раз.
def collate(array)
transformations = array.inject({}) do |hash, item|
лучше, но мы еще не учли прописные буквы и эквивалентность символов. Возьмем для примера немецкий язык.
На самом деле в немецком языке есть несколько способов упорядочения; мы остановимся на стандарте DIN-2 (как в телефонном справочнике). Согласно этому стандарту, символ ss (эсцет) эквивалентен ss, а умляут эквивалентен букве е (то есть "o — то же самое, что ое и т.д.).
Наш метод трансформации должен учитывать эти детали. Снова начнем с декомпозиции составных символов. Например, модифицирующая трема (умляут) представляется кодовой позицией
U+0308
. За основу мы возьмем метод преобразования регистра, имеющийся в Ruby, но несколько дополним его. Вот как выглядит теперь код трансформации:
He для всех языков годится такой прямолинейный подход. Например, в испанском между буквами n и о есть еще буква ~n. Однако, если каким-то образом сдвинуть оставшиеся буквы, то мы справимся и с этой проблемой. В листинге 4.1 для упрощения обработки нормализация применена к монолитным символам. Кроме того, мы облегчили себе жизнь, игнорируя различия между буквами с диакритическими знаками и без них.
реальности упорядочение немного сложнее, чем показано в примерах выше; обычно требуется до трех уровней обработки. На первом уровне сравниваются только базовые символы без учета диакритических знаков и регистра, на втором учитываются диакритические знаки, а на третьем — регистр. Второй и третий уровень необходимы лишь в том случае, когда на предыдущих уровнях строки совпали. Кроме того, в некоторых языках последовательности, состоящие из нескольких символов, сортируются как единая семантическая единица (например, в хорватском lj расположено между l и m). Поэтому разработка языковозависимого или обобщенного алгоритма сортировки — задача нетривиальная: необходимо хорошо разбираться в конкретном языке. Невозможно изобрести по-настоящему универсальный алгоритм сортировки, который давал бы правильные результаты для всех языков, хотя попытки в этом направлении производились.
4.2.6. Преобразование из одной кодировки в другую
В стандартной библиотеке Ruby имеется интерфейс к библиотеке
iconv
для преобразования из одной кодировки символов в другую. Она должна работать на всех платформах, в том числе и в Windows (если дистрибутив устанавливался моментальным инсталлятором).
Чтобы преобразовать строку из UTF-8 в ISO-8859-15, библиотека
iconv
используется следующим образом:
require 'iconv'
converter = Iconv.new('ISO-8859-15', 'UTF-8')
sword_iso = converter.iconv(sword)
Важно помнить, что сначала указывается целевая кодировка, а потом исходная (как при присваивании). Количество и названия поддерживаемых кодировок зависят от платформы, но наиболее распространенные стандартизованы и имеются везде. Если установлена пакетная утилита
iconv
, то перечень распознаваемых кодировок можно получить с помощью команды
iconv -l
.
Помимо названия кодировки,
iconv
принимает еще флаги, управляющие ее поведением. Они указываются в конце строки, содержащей целевую кодировку.
Обычно
iconv
возбуждает исключение, если получает недопустимые входные данные или почему-либо не может представить их в целевой кодировке. Флаг
//IGNORE
подавляет исключение.
broken_utf8_string = "hello\xfe"
converter = Iconv.new('ISO-8859-15', 'UTF-8')
# будет возбуждено исключение Iconv::IllegalSequence