единая семантическая единица (например, в хорватском 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 = 'helloxfe'
converter = Iconv.new('ISO-8859-15', 'UTF-8')
# будет возбуждено исключение Iconv::IllegalSequence
converter.iconv(broken_utf8_string)
converter = Iconv.new('ISO-8859-15//IGNORE', 'UTF-8')
converter.iconv(broken_utf8_string) # 'hello'
Этот же флаг позволяет очистить строку от неверных данных:
broken_sword = 'épéexfe'
converter = Iconv.new('UTF-8//IGNORE', 'UTF-8')
converter.iconv(broken_sword) # 'épée'
Иногда некоторые символы нельзя представить в целевой кодировке. Обычно в этом случае возбуждается исключение. Флаг //TRANSLIT
говорит iconv
, что нужно вместо этого попытаться подобрать приблизительные эквиваленты.
converter = Iconv.new('ASCII', 'UTF-8')
converter.iconv(sword) # Возбуждается Iconv::IllegalSequence.
converter = Iconv.new('ASCII//IGNORE', 'UTF-8')
converter.iconv(sword) # 'pe'
converter = Iconv.new('ASCII//TRANSLIT', 'UTF-8')
converter.iconv(sword) # ''ep'ee'
Этим свойством можно воспользоваться, чтобы получить URL, содержащий только ASCII- символы:
str = 'Straße épée'
converter = Iconv.new('ASCII//TRANSLIT', 'UTF-8')
converter.iconv(sword).gsub(/ /, '-').gsub(/[^а-z-]/in).downcase
# 'strasse-epee'
Однако работать это будет лишь в отношении латиницы. В листинге 4.2 приведен реальный пример совместного применения библиотек iconv
и open-uri
для скачивания Web- страницы и перекодирования ее в UTF-8.
require 'open-uri'
require 'iconv'
def get_web_page_as_utf8(url)
open(url) do |io|
source = io.read
type, *parameters = io.content_type_parse
# He перекодировать, если не (X)HTML
unless type =~ %r!^(?:text/html|application/xhtml+xml)$!
return source
end
# Сначала проверяем заголовки, присланные сервером:
if pair = parameters.assoc('charset')
encoding = pair.last
# Затем анализируем HTML:
elsif source =~ ?]*?charset=([^s'']+)/i
encoding = $1
# Если не удалось определить, предполагаем кодировку по умолчанию,
# определенную в стандарте HTTP.
else
encoding = 'ISO-8859-1'
end
converter = Iconv.new('UTF-8//IGNORE', encoding)
return converter.iconv(source)
end
end
Это еще не все системные вопросы, связанные с преобразованием кодировок. Предположим, что в операционной системе, где установлен Ruby, определена локаль, отличная от UTF-8, или Ruby общается с ОС не в UTF-8 (так, например, обстоит дело в дистрибутиве для Win32). Тогда возникают дополнительные сложности.
Например, Windows поддерживает Unicode в именах файлов и на системном уровне работает исключительно в Unicode. Но в настоящее время Ruby взаимодействует с Windows при помощи устаревших кодовых страниц. Для англоязычного и большинства других западных изданий это страница 1252 (или WINDOWS-1252
).
Внутри программы можно пользоваться и кодировкой UTF-8, но все имена файлов придется перевести в кодировку, заданную кодовой страницей. Iconv поможет это сделать, но важно не забывать, что кодовая страница позволяет описать только малое подмножество всех символов, имеющихся в Unicode.
Кроме того, это означает, что пока Ruby для Windows не может открывать файлы, имена которых нельзя описать с помощью кодовой страницы. Это ограничение не относится к Mac OS X, Linux и другим системам с локалью UTF-8.