- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Программирование на языке Ruby - Хэл Фултон
Шрифт:
Интервал:
Закладка:
ascii_string[0,20]
Однако, поскольку кодовая позиция Unicode может занимать более одного байта такую технику нельзя безопасно применять к строке в кодировке UTF-8. Есть риск, что в конце строки окажется недопустимая последовательность байтов. Кроме того, это не слишком полезно, так как мы не можем заранее сказать, сколько в результате получится кодовых позиций. На помощь приходят регулярные выражения:
def truncate(str, max_length)
str[/.{0,#{max_length}}/m]
end
4.2.3. Распознавание кодировки
Распознать, в какой кодировке записана данная строка, довольно сложно. Многобайтовые кодировки обладают отличительными признаками, по которым их можно опознать, но с однобайтовыми — а именно они применяются в западных языках — дело обстоит куда хуже. Для решения можно применить статистические методы, но эта тема выходит за рамки данной книги (к тому же результат в общем случае получается не слишком надежным).
К счастью, обычно перед нами стоит более простая задача — выяснить, записана ли строка в кодировке UTF-8. На этот вопрос можно дать достаточно надёжный ответ. Приведем один способ (основанный на том, что метод unpack возбуждает исключение, если ему передана некорректная строка):
class String
def utf8?
unpack('U*') rescue return false
true
end
end
4.2.4. Нормализация Unicode-строк
До сих пор мы пользовались монолитными символами, в которых базовый символ и диакритический знак объединены в одну кодовую позицию. Но, вообще говоря, в Unicode символы и диакритические знаки представлены отдельно. Вместо того чтобы хранить букву é в кодовой позиции СТРОЧНАЯ ЛАТИНСКАЯ БУКВА E С АКУТОМ, можно было бы представить ее в составной форме как СТРОЧНУЮ ЛАТИНСКУЮ БУКВУ E и МОДИФИЦИРУЮЩИЙ АКУТ.
Для чего это может понадобиться? Для обеспечения дополнительной гибкости и возможности применять диакритические знаки к любому символу, а не ограничивать себя комбинациями, которые предусмотрел проектировщик кодировки. На самом деле в шрифты включены глифы для наиболее распространенных комбинаций символа и диакритического знака, но отображение символа и его кодирование — вещи разные.
При проектировании Unicode приходилось учитывать такие вещи, как эффективность и совместимость с существующими национальными кодировками. Иногда это приводит к избыточности; например, в Unicode имеются кодовые позиции как для составных форм, так и для многих уже применяющихся монолитных форм.
Рассмотрим, к примеру, немецкое слово «öffnen» (открывать). Даже если забыть о регистре, его можно закодировать четырьмя способами:
1. о + МОДИФИЦИРУЮЩАЯ ТРЕМА (u+0308) +f+f+n+e+n
2. СТРОЧНАЯ ЛАТИНСКАЯ БУКВА О С ТРЕМОЙ (U+00F6) + f + f + n + е + n
3. о + МОДИФИЦИРУЮЩАЯ ТРЕМА + ЛИГАТУРА ДВОЙНОЕ F (U+FB00) + n + е + n.
4. СТРОЧНАЯ ЛАТИНСКАЯ БУКВА О С ТРЕМОЙ + ЛИГАТУРА ДВОЙНОЕ F + n + e + n
Трема — это две точки над буквой (в немецком языке называется «умляут»).
Нормализацией называется процедура приведения разных представлений символа к стандартной форме. Можно быть уверенным, что после нормализации данный символ закодирован вполне определенным образом. Каким именно, зависит оттого, чего мы хотим достичь. В приложении 15 к стандарту Unicode перечислены четыре формы нормализации:
1. Форма D (каноническая декомпозиция).
2. Форма С (каноническая декомпозиция с последующей канонической композицией).
3. Форма KD (совместимая декомпозиция).
4. Форма KC (совместимая декомпозиция с последующей канонической композицией).
Иногда можно встретить аббревиатуры NKFC (Normalization Form KC) и т.д.
Точные правила, сформулированные в стандарте, довольно сложны; в них проведено различие между «канонической эквивалентностью» и «совместимой эквивалентностью». (Корейский и японский языки требуют особого рассмотрения, но мы не станем тратить на это время.) В таблице 4.2 показано, как форма нормализации влияет на приведенные выше строки.
Таблица 4.2. Нормализованные формы в Unicode
Исходная NFD NFC NFKD NFKC o+ ̈+f+f+n+e+n o+ ̈+f+f+n+e+n ö+f+f+n+e+n o+ ̈+f+f+n+e+n ö+f+f+n+e+n ö+f+f+n+e+n o+ ̈+f+f+n+e+n ö+f+f+n+e+n o+ ̈+f+f+n+e+n ö+f+f+n+e+n o+ ̈+ff+n+e+n o+ ̈+ff+n+e+n ö+ff+n+e+n o+ ̈+f+f+n+e+n ö+f+f+n+e+n ö+ff+n+e+n o+ ̈+ff+n+e+n ö+ff+n+e+n o+ ̈+f+f+n+e+n ö+f+f+n+e+nФормы С и D обратимы, KC и KD — нет. С другой стороны, потеря некоторых данных в формах KC и KD — свидетельство того, что все четыре строки двоично эквивалентны. Какая форма лучше всего подходит, зависит от приложения. Мы ещё вернемся к этой теме в следующем разделе.
Для Ruby есть библиотека, позволяющая выполнить описанные нормализации, хотя в стандартный дистрибутив она не входит. Вы можете скачать ее со страницы http://www.yoshidam.net/Ruby.html и установить командой gem install Unicode.
Если библиотека Unicode установлена, то для выполнения любой нормализации достаточно вызвать один из методов Unicode.normalize_x:
require 'Unicode'
sword_kd = Unicode.normalize_KD(sword)
sword_kd.scan(/./) # ["e", "'", "p", "e", "'", "e"]
sword_kc = Unicode.normalize_KC(sword)
sword_kc.scan(/./) # [ "é", "p", "é", "e"]
4.2.5. Упорядочение строк
Обычно, хотя и не всегда, строки упорядочиваются по алфавиту или сходным образом. Упорядочение тесно связано с нормализацией: в обоих случаях применяются одни и те же идеи и библиотеки.
Предположим, например, что мы хотим отсортировать такой массив строк:
eacute = [0x00Е9].pack('U')
acute = [0x0301].pack('U')
array = ["epicurian", "#{eacute}p#{eacute}e", "e#{acute}lan"]
# ["epicurian", "éрéе", "élan"]
Что произойдет, если передать этот массив методу Array#sort?
array.sort # ["epicurian", "élan", "éрéе"]
He годится!.. Попытаемся понять, почему так получилось. Сортируемые строки Ruby сравнивает побайтно. Чтобы убедиться в этом, достаточно взглянуть на первые несколько байтов каждой строки:
array.map {|item| "#{item}: #{item.unpack('С*')[0,3].join(',')}" }
# ["epicurian: 101,112,105", "éрéе: 195,169,112",
# "élan: 101,204,129"]
Тут возникают две трудности. Во-первых, символы UTF-8, не имеющие аналога в кодировке ASCII, начинаются с байта, имеющего большое числовое значение, а стало быть, после сортировки неизбежно окажутся после ASCII-символов. Во-вторых, составные латинские символы оказываются раньше монолитных из-за первого ASCII-байта.
В системные библиотеки обычно включают функции сортировки, которые сравнивают строки в соответствии с правилами конкретного языка. В библиотеке, поставляемой вместе с компилятором языка С, для этого служат функции strxfrm и strcoll.
Имейте в виду, что проблема возникает даже в случае кодировки ASCII. При сортировке ASCII-строк в Ruby производится прямое лексикографическое сравнение, однако в реальной жизни (например, если мы хотим отсортировать по названиям книги из библиотеки Конгресса США) есть много правил, которые не учитываются при таком упрощенном подходе.
Для упорядочения строк можно создать промежуточные строки и отсортировать именно их. Как конкретно это сделать, зависит от предъявляемых требований и языка; универсального алгоритма не существует.
Предположим, что список обрабатывается согласно правилам английского языка, причем диакритические знаки игнорируются. Первым делом нужно определить методику трансформации. Мы приведем все символы к составному виду, а затем исключим диакритические знаки, оставив только базовые символы. Для модифицирующих диакритических знаков в Unicode выделен диапазон от U+0300 to U+036F:
def transform(str)
Unicode.normalize_KD(str).unpack('U*').select{ |cp|
cp < 0x0300 || cp > 0x036F
}.pack('U*')
end
array.map{|x| transform(x) } # ["epicurian", "epee", "elan"]
Затем создадим хэшированную таблицу, чтобы установить соответствие между исходными и трансформированными строками, и воспользуемся ей для сортировки исходных строк. Наличие такой таблицы позволяет провести трансформацию только один раз.
def collate(array)