позицией, которая не находится на границе слова (B
). Примеры использования метода gsub
показывают, как эти якоря работают:
str = 'this is a test'
str.gsub(//,'|') # '|this| |is| |a| |test|'
str.gsub(/В/, '-') # 't-h-i-s i-s a t-e-s-t'
He существует способа отличить начало слова от конца.
3.5. Кванторы
Немалая часть аппарата регулярных выражений связана с обработкой необязательных элементов и повторений. Элемент, за которым следует вопросительный знак, необязателен; он может присутствовать или отсутствовать, а общее соответствие зависит от прочих частей регулярного выражения. (Этот квантор имеет смысл применять только к подвыражению ненулевой длины, но не к якорям.)
pattern = /ax?b/
pat2 = /а[xy]?b/
pattern =~ 'ab' # 0
pattern =~ 'acb' # nil
pattern =~ 'axb' # 0
pat2 =~ 'ayb' # 0
pat2 =~ 'acb' # nil
Элементы часто повторяются неопределенное число раз (для формулировки этого условия служит квантор +
). Например, следующий образец соответствует любому положительному числу:
pattern = /[0-9]+/
pattern =~ '1' # 0
pattern =~ '2345678' # 0
Еще один типичный случай — образец, повторяющийся нуль или более раз. Конечно, это условие можно выразить с помощью кванторов +
и ?
. Вот, например, как сказать, что после строки Huzzah должно быть нуль или более восклицательных знаков:
pattern = /Huzzah(!+)?/ # Скобки здесь обязательны.
pattern =~ 'Huzzah' # 0
pattern =~ 'Huzzah!!!!' # 0
Но есть и способ лучше. Требуемое поведение описывается квантором *
.
pattern = /Huzzah!*/ # * применяется только к символу !
pattern =~ 'Huzzah' # 0
pattern =~ 'Huzzah!!!!' # 0
Как распознать американский номер социального страхования? С помощью такого образца:
ssn = '987-65-4320'
pattern = /ddd-dd-dddd/
pattern =~ ssn # 0
Но это не вполне понятно. Лучше явно сказать, сколько цифр должно быть в каждой группе. Это можно сделать, указав число повторений в фигурных скобках:
pattern = /d{3}-d{2}-d{4}/
Необязательно, что такой образец будет короче, но он более понятен читателю программы.
Можно также использовать диапазоны, границы которых разделены запятой. Предположим, что номер телефона в Элбонии состоит из двух частей: в первой может быть от трех до пяти цифр, а во второй — от трех до семи. Вот как выглядит соответствующий образец:
elbonian_phone = /d{3,5}-d{3,7}/
Нижняя и верхняя границы диапазона необязательны (но хотя бы одна должна быть задана):
/x{5}/ # Соответствует 5 x.
/x{5,7}/ # Соответствует 5-7 x.
/x{,8}/ # Соответствует не более 8 x.
/x{3,}/ # Соответствует по меньшей мере 3 x.
Ясно, что кванторы ?
, +
и *
можно переписать и так:
/x?/ # То же, что /x{0,1}/
/x*/ # То же, что /x{0,}
/x+/ # то же, что /x{1,}
Фразеология, применяемая при описании регулярных выражений, изобилует яркими терминами: жадный (greedy), неохотный (reluctant), ленивый (lazy) и собственнический (possessive). Самым важным является различие между жадными и нежадными выражениями.
Рассмотрим следующий фрагмент кода. На первый взгляд, это регулярное выражение должно сопоставляться со строкой 'Where the'
, но на самом деле ему соответствует более длинная подстрока 'Where the sea meets the'
:
str = 'Where the sea meets the moon-blanch'd land,'
match = /.*the/.match(str)
p match[0] # Вывести полученное соответствие:
# 'Where the sea meets the'
Причина состоит в том, что оператор *
выполняет жадное сопоставление, то есть продвигается так далеко по строке, как только можно, в поисках самого длинного соответствия. Чтобы излечить его от жадности, нужно добавить вопросительный знак:
str = 'Where the sea meets the moon-blanch'd land,'
match = /.*?the/.match(str)
p match[0] # Вывести полученное соответствие:
# 'Where the' .
Итак, оператор *
жадный, если за ним не стоит ?
. То же самое относится к кванторам +
и {m,n}
и даже к самому квантору ?
.
Я не сумел найти разумных примеров применения конструкций {m,n}?
и ??
. Если вам о них известно, пожалуйста, поделитесь со мной своим опытом.
Дополнительная информация о кванторах содержится в разделе 3.13.
3.6. Позитивное и негативное заглядывание вперед
Понятно, что регулярное выражение сопоставляется со строкой линейно (осуществляя при необходимости возвраты). Поэтому существует понятие «текущего положения» в строке, это аналог указателя файла или курсора.
Термин «
В следующем примере строка 'New world'
будет сопоставлена, если за ней следует одна из строк 'Symphony'
или 'Dictionary'
. Однако третье слово не будет частью соответствия.
s1 = 'New World Dictionary'