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 = /(\d\d)\/(\d\d)\/(\d\d) (\d\d): (\d\d): (\d\d)/
.
Но такой образец распознает некоторые некорректные даты и отвергает правильные. Следующий вариант более избирателен. Обратите внимание, как мы строим его путем интерполяции мелких регулярных выражений в более крупное:
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 = /(\d\d)/ # 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 и т. д.
(\d\d) [ ] # 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]+) +\1\b/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/