- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Программирование на языке Ruby - Хэл Фултон
Шрифт:
Интервал:
Закладка:
3.14.1. Сопоставление с IP-адресом
Пусть мы хотим понять, содержит ли строка допустимый IPv4-адрес. Стандартно он записывается в точечно-десятичной нотации, то есть в виде четырех десятичных чисел, разделенных точками, причем каждое число должно находиться в диапазоне от 0 до 255.
Приведенный ниже образец решает эту задачу (за немногими исключениями типа «127.1»). Для удобства восприятия мы разобьем его на части. Отметим, что символ d дважды экранирован, чтобы косая черта не передавалась из строки в регулярное выражение (чуть ниже мы решим и эту проблему).
num = "(\d|[01]?\d\d|2[0-4]\d25[0-5])"
pat = ^(#{num}.){3}#{num}$"
ip_pat = Regexp.new(pat)
ip1 = "9.53.97.102"
if ip1 =~ ip_pat # Печатается: "да"
puts "да"
else
puts "нет"
end
Надо признать, что в определении переменной num слишком много символов обратной косой черты. Определим ее в виде регулярного выражения, а не строки:
num = /(d1[01]?dd|2[0-4]d|25[0-5])/
Когда одно регулярное выражение интерполируется в другое, вызывается метод to_s, который сохраняет всю информацию из исходного регулярного выражения.
num.to_s # "(?-mix:(\d|[01]?\d\d|2[0-4]\d|25[0-5]))"
Иногда для встраивания удобно использовать регулярное выражение, а не строку. Хорошее эвристическое правило: интерполируйте регулярные выражения, если веских причин интерполировать строки.
IPv6-адреса пока не очень широко распространены, но для полноты рассмотрим и их. Они записываются в виде восьми шестнадцатеричных чисел, разделенных двоеточиями, с подавлением начальных нулей.
num = /[0-9A-Fa-f]{0,4}/
pat = /^(#{num}:){7}#{num}$/
ipv6_pat = Regexp.new(pat)
v6ip = "abcd::1324:ea54::dead::beef"
if v6ip =~ ipv6_pat # Печатается: "да"
puts "да"
else
puts "нет"
end
3.14.2. Сопоставление с парой «ключ-значение»
Иногда приходится работать со строками вида «ключ=значение» (например, при разборе конфигурационного файла приложения).
Следующий код извлекает ключ и значение. Предполагается, что ключ состоит из одного слова, значение продолжается до конца строки, а знак равенства может быть окружен пробелами:
pat = /(w+)s*=s*(.*?)$/
str = "color = blue"
matches = pat.match(str)
puts matches[1] # "color"
puts matches[2] # "blue"
3.14.3. Сопоставление с числами, записанными римскими цифрами
Следующее довольно сложное регулярное выражение сопоставляется с любым правильно записанным римскими цифрами числом (до 3999 включительно). Как и раньше, для удобства восприятия образец разбит на части:
rom1 = /m{0,3}/i
rom2 = /(d?c{0,3}|с[dm])/i
rom3 = /(l?x{0,3}|x[lс])/i
rom4 = /(v?i{0,3}|i[vx])/i
roman = /^#{rom1}#{rom2}#{rom3}#{rom4}$/
year1985 = "MCMLXXXV"
if year1985 =~ roman # Печатается: "да"
puts "да"
else
puts "нет"
end
Возможно, у вас появилось искушение поставить в конец всего выражения модификатор i, чтобы сопоставлялись и строчные буквы:
# Это не работает!
rom1 = /m{0,3}/
rom2 = /(d?c{0,3}|с[dm])/
rom3 = /(l?x{0,3}|x[lс])/
rom4 = /(v?i{0,3}|i[vx])/
roman = /^#{rom1}#{rom2}#{rom3}#{rom4}$/i
Почему такое выражение не годится? Взгляните на этот пример и поймете:
rom1.to_s # "(?-mix:m{0,3})"
Обратите внимание, что метод to_s запоминает флаги для каждого выражения; тем самым флаг всего выражения перекрывается.
3.14.4 Сопоставление с числовыми константами
Сопоставление с простым целым десятичным числом — самое простое. Число состоит из необязательного знака и последовательности цифр (правда, Ruby позволяет использовать знак подчеркивания в качестве разделителя цифр). Отметим, что первая цифра не должна быть нулем, иначе число будет интерпретироваться как восьмеричное.
int_pat = /^[+-]?[1-9][d_]*$/
Целые константы в других системах счисления обрабатываются аналогично. Образцы для шестнадцатеричных и двоичных чисел сделаны не чувствительными к регистру, так как они содержат букву:
hex_pat = /^[+-]?0x[da-f_]+$/i
oct_pat = /^[+-]?0[0-7_]+$/
bin_pat = /^[+-]?0b[01_]+$/i
Сопоставить число с плавающей точкой в обычной нотации несколько сложнее. Последовательности цифр по обе стороны десятичной точки необязательны, но хотя бы одна цифра должна быть:
float_pat = /^(d[d_]*)*.[d_]*$/
Образец для чисел, записанных в научной нотации, основан на предыдущем:
sci_pat = /^(d[d_]*)?.[d_]*(e[+-]?)?(_*d[d_]*)$/i
Эти образцы могут оказаться полезны, если вы хотите убедиться, что строка содержит число, перед тем как пытаться преобразовать ее.
3.14.5 Сопоставление с датой и временем
Пусть надо выделить дату и время, записанные в формате mm/dd/yy hh:mm:ss. Вот первая попытка: datetime = /(dd)/(dd)/(dd) (dd): (dd): (dd)/.
Но такой образец распознает некоторые некорректные даты и отвергает правильные. Следующий вариант более избирателен. Обратите внимание, как мы строим его путем интерполяции мелких регулярных выражений в более крупное:
mo = /(0?[1-9]|1[0-2])/ # От 01 до 09 или от 1 до 9 или 10-12.
dd = /([0-2]?[1-9]| [1-3][01])/ # 1-9 или 01-09 или 11-19 и т.д.
yy = /(dd)/ # 00-99
hh = /([01]?[1-9]|[12][0-4])/ # 1-9 или 00-09 или...
mi = /([0-5]d)/ # 00-59, обе цифры должны присутствовать.
ss = /([0-6]d)?/ # разрешены еще и доли секунды ;-)
date = /(#{mo}/#{dd}/#{yy})/
time = /{#{hh}:#{mi}:#{ss})/
datetime = /(#{date} #{time})/
Вот как можно вызвать это регулярное выражение из метода String#scan, чтобы получить массив соответствий:
str="Recorded on 11/18/07 20:31:00"
str.scan(datetime)
# [["11/18/07 20:31:00", "11/18/07", "11", "18", "00",
# "20:31:00", "20", "31", ":00"]]
Разумеется, все это можно было сделать с помощью одного большого регулярного выражения:
datetime = %r{(
(0?[1-9]|1[0-2])/ # mo: от 01 до 09 или от 1 до 9 или 10-12.
([0-2]?[1-9]|[1-3][01])/ # dd: 1-9 или 01-09 или 11-19 и т. д.
(dd) [ ] # yy: 00-99
([01]?[1-9]|[12][0-4]): # hh: 1-9 или 00-09 или...
([0-5]d): # mm: 00-59, обе цифры должны присутствовать.
(([0-6]d))? # ss: разрешены еще и доли секунды ;-)
)}x
Обратите внимание на конструкцию %r{}, позволяющую не экранировать символы обратной косой черты.
3.14.6. Обнаружение повторяющихся слов в тексте
В этом разделе мы реализуем детектор повторяющихся слов. Повторение одного и того же слова два раза подряд — типичная опечатка. Следующий код распознает такие ситуации:
double_re = /b(['A-Z]+) +1b/i
str="There's there's the the pattern."
str.scan(double_re) # [["There's"],["the"]]
Обратите внимание на модификатор i в конце выражения, он позволяет проводить сопоставление без учета регистра. Каждой группе соответствует массив, поэтому в результате получается массив массивов.
3.14.7. Поиск слов, целиком набранных прописными буквами
Мы упростили пример, предположив, что в тексте нет чисел, подчерков и т.д.
allcaps = /b[A-Z]+b/
string = "This is ALL CAPS"
string[allcaps] # "ALL"
Suppose you want to extract every word in all-caps:
string.scan(allcaps) # ["ALL", "CAPS"]
При желании можно было бы обобщить эту идею на идентификаторы Ruby и аналогичные вещи.
3.14.8. Сопоставление с номером версии
Принято присваивать библиотекам и приложениям номера версий, состоящие из трёх чисел, разделенных точками. Следующее регулярное выражение сопоставляется с подобной строкой, выделяя попутно имя пакета и отдельные части номера версии:
package = "mylib-1.8.12"
matches = package.match(/(.*)-(d+).(d+).(d+)/)
name, major, minor, tiny = matches[1..-1]
3.14.9. Еще несколько образцов
Завершим наш список несколькими выражениями из категории «разное». Как обычно, почти все эти задачи можно решить несколькими способами.
Пусть нужно распознать двузначный почтовый код американского штата. Проще всего, конечно, взять выражение /[A-Z]{2}/. Но оно сопоставляется с такими строками, как XX или ZZ, которые допустимы, но бессмысленны. Следующий образец распознает все стандартные аббревиатуры, общим числом 51 (50 штатов и DC — округ Колумбия):
state = /^A[LKZR] ! C[AOT] | D[EC] | FL | GA | HI | I[DLNA] |
K[SY] | LA | M[EDAINSOT] | N[EVHJMYCD] | O[HKR] |
PA | RI | S[CD] | T[NX] | UT | V[TA] | W[AVIY]$/x
Для ясности я воспользовался обобщенным регулярным выражением (модификатор x). Пробелы и символы новой строки в нем игнорируются.