понимать, что смещение конца — это индекс символа, следующего за найденным соответствием.)
str = 'alpha beta gamma delta epsilon'
# 0....5....0....5....0....5....
# (для удобства подсчета)
pat = /(b[^ ]+ )(g[^ ]+ )(d[^ ]+ )/
# Три слова, каждое из которых представляет собой отдельное соответствие.
refs = pat.match(str)
# 'beta '
p1 = refs.begin(1) # 6
p2 = refs.end(1) # 11
# 'gamma '
p3 = refs.begin(2) # 11
p4 = refs.end(2) # 17
# 'delta '
p5 = refs.begin(3) # 17
p6 = refs.end(3) # 23
# 'beta gamma delta'
p7 = refs.begin(0) # 6
p8 = refs.end(0) # 23
Аналогично метод offset
возвращает массив из двух чисел: смещение начала и смещение конца соответствия. Продолжим предыдущий пример:
range0 = refs.offset(0) # [6,23]
range1 = refs.offset(1) # [6,11]
range2 = refs.offset(2) # [11,17]
range3 = refs.offset(3) # [17,23]
Части строки, которые находятся перед сопоставленной подстроки и после нее, можно получить методами pre_match
и post_match
соответственно. В том же коде:
before = refs.pre_match # 'alpha '
after = refs.post_match # 'epsilon'
3.8. Классы символов
/[aeiou]/ # Соответствует любой из букв а, е, i, о, и; эквивалентно
# /(a|e|i|o|u)/, только группа не запоминается.
Внутри класса символов управляющие последовательности типа
по-прежнему распознаются, но такие метасимволы, как .
и ?
, не имеют специального смысла:
/[.
?]/ # Сопоставляется с точкой, символом новой строки,
# вопросительным знаком.
Символ каре (^
) внутри класса символов имеет специальный смысл, если находится в начале; в этом случае он формирует дополнение к списку символов:
[^aeiou] # Любой символ, КРОМЕ а, е, i, о, и.
Дефис внутри класса символов обозначает диапазон (в лексикографическом порядке):
/[а-mA-М]/ # Любой символ из первой половины алфавита.
/[^а-mA-М]/ # Любой ДРУГОЙ символ, а также цифры и символы. отличные
# от букв и цифр.
Дефис в начале или в конце класса символов, а также каре в середине теряют специальный смысл и интерпретируются буквально. То же относится к левой квадратной скобке, но правая квадратная скобка, очевидно, должна экранироваться:
/[-^[]]/ # Сопоставляется с дефисом, каре и правой квадратной скобкой.
Регулярные выражения в Ruby могут содержать ссылки на именованные классы символов вида [[:name:]]
. Так, [[:digit:]]
означает то же самое, что образец [0-9]
. Во многих случаях такая запись оказывается короче или, по крайней мере, понятнее.
Есть еще такие именованные классы: [[:print:]]
(символы, имеющие графическое начертание) и [[:alpha:]]
(буквы):
s1 = 'abc 07def'
/[[:print:]]*/.match(s1)
m1 = Regexp::last_match[0] # 'abc'
s2 = '1234def'
/[[:digit:]]*/.match(s2)
m2 = Regexp::last_match[0] # '1234'
/[[:digit:]] + [[:alpha:]]/.match(s2)
m3 = Regexp::last_match[0] # '1234d'
Каре перед именем класса символов формирует его дополнение:
/[[:^alpha:]]/ # Все символы, кроме букв.
Для многих классов имеется также сокращенная нотация. Наиболее распространены сокращения d
(любая цифра), w
(любой символ, входящий в состав «слова») и s
(пропуски — пробел, знак табуляции или новой строки):
str1 = 'Wolf 359'
/w+/.match(str1) # Соответствует 'Wolf' (то же, что /[a-zA-Z_0-9]+/)
/w+ d+/.match(str1) # Соответствует 'Wolf 359'
/w+ w+/.match(str1) # Соответствует 'Wolf 359'
/s+/.match(str1) # Соответствует ' '
«Дополнительные» формы обычно записываются в виде прописной буквы:
/W/ # Любой символ, не входящий в состав слова.
/D/ # Все кроме цифр.
/S/ # Все кроме пропусков.
Дополнительная информация, относящаяся только к Oniguruma, приводится в разделе 3.13.
3.9. Обобщенные регулярные выражения
Регулярные выражения, особенно длинные, часто выглядят загадочно. Модификатор x
позволяет записывать регулярное выражение на нескольких строках. При этом пробелы и символы новой строки игнорируются, так что можно делать для наглядности отступы. Заодно разрешается оставлять комментарии, хотя это возможно даже в простых регулярных выражениях.
Чтобы привести несколько искусственный пример умеренно сложного регулярного выражения, предположим, что имеется такой список адресов:
addresses =
[ '409 W Jackson Ave', 'No. 27 Grande Place',
'16000 Pennsylvania Avenue', '2367 St. George St.',