Категории
Самые читаемые
Лучшие книги » Компьютеры и Интернет » Программирование » Программирование на языке Ruby - Хэл Фултон

Программирование на языке Ruby - Хэл Фултон

Читать онлайн Программирование на языке Ruby - Хэл Фултон

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 33 34 35 36 37 38 39 40 41 ... 156
Перейти на страницу:

def collate(array)

 transformations = array.inject({}) do |hash, item|

  hash[item] = yield item

  hash

 end

 array.sort_by {|x| transformations[x] }

end

collate(array) {|a| transform(a) } # ["élan", "épée", "epicurian"]

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

На самом деле в немецком языке есть несколько способов упорядочения; мы остановимся на стандарте DIN-2 (как в телефонном справочнике). Согласно этому стандарту, символ ß (эсцет) эквивалентен ss, а умляут эквивалентен букве е (то есть ö — то же самое, что ое и т.д.).

Наш метод трансформации должен учитывать эти детали. Снова начнем с декомпозиции составных символов. Например, модифицирующая трема (умляут) представляется кодовой позицией U+0308. За основу мы возьмем метод преобразования регистра, имеющийся в Ruby, но несколько дополним его. Вот как выглядит теперь код трансформации:

def transform_de(str)

 decomposed = Unicode.normalize_KD(str).downcase

 decomposed.gsub!('ß', 'ss')

 decomposed.gsub([0x0308].pack('U'), 'e')

end

array = ["Straße", "öffnen"]

array.map {|x| transform_de(x) } # ["strasse", "oeffnen"]

He для всех языков годится такой прямолинейный подход. Например, в испанском между буквами n и о есть еще буква ñ. Однако, если каким-то образом сдвинуть оставшиеся буквы, то мы справимся и с этой проблемой. В листинге 4.1 для упрощения обработки нормализация применена к монолитным символам. Кроме того, мы облегчили себе жизнь, игнорируя различия между буквами с диакритическими знаками и без них.

Листинг 4.1. Упорядочение строк в испанском языке

def map_table(list)

 table = {}

 list.each_with_index do |item, i|

  item.split(',').each do |subitem|

   table[Unicode, normalize_KC(subitem)] = (?a + i).chr

  end

 end

 table

end

ES_SORT = map_table(%w(

 a,A,á,Á b,B c,C d,D е,Е,é,É f,F g,G h,H i,I,í,Í j,J k,K l,L m,M

 n,N ñ,Ñ o,O,ó,Ó p,P q,Q r,R s,S t,T u,U,u,U v,V w,W x,X y,Y z,Z

))

def transform_es(str)

 array = Unicode.normalize_KC(str).scan(/./u)

 array.map {|c| ES_SORT[c] || c}.join

end

array = %w[éste estoy año apogeo amor]

array.map {|a| transform_es(a) }

# ["etue", "etupz", "aop", "aqpgep", "amps"]

collate(array) {|a| transform_es(a) }

# ["amor", "año", "apogeo", "éste", "estoy"]

В реальности упорядочение немного сложнее, чем показано в примерах выше; обычно требуется до трех уровней обработки. На первом уровне сравниваются только базовые символы без учета диакритических знаков и регистра, на втором учитываются диакритические знаки, а на третьем — регистр. Второй и третий уровень необходимы лишь в том случае, когда на предыдущих уровнях строки совпали. Кроме того, в некоторых языках последовательности, состоящие из нескольких символов, сортируются как единая семантическая единица (например, в хорватском 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.

Листинг 4.2. Перекодирование 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.

4.3. Справочники сообщений

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

Nick Nicholas, John Cowan. What is Lojban?

Справочник сообщений — это набор сообщений на одном языке. Данное понятие неотъемлемо от концепции локализации (L10N). Идея в том, чтобы отделить языково-зависимые строки от остальной программы. Тогда для того, чтобы программа «заговорила» на другом языке, достаточно всего лишь подменить справочник.

«Наилучший» способ реализовать эту идею в Ruby — воспользоваться библиотекой Ruby-GetText-Package. Я буду называть ее просто gettext, поскольку именно так называется содержащий ее файл (не путайте с утилитой gettext!). Эту великолепную библиотеку написал Macao Муто (Masao Mutoh), он же очень помог при написании данного раздела.

1 ... 33 34 35 36 37 38 39 40 41 ... 156
Перейти на страницу:
На этой странице вы можете бесплатно скачать Программирование на языке Ruby - Хэл Фултон торрент бесплатно.
Комментарии