logo search
Программирование на языке Ruby

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{}, позволяющую не экранировать символы обратной косой черты.