Книга: Программирование на языке Ruby

3.13.6. Именованные соответствия

3.13.6. Именованные соответствия

Специальной формой подвыражения является именованное выражение, которое позволяет присвоить образцу имя (а не просто порядковый номер).

Синтаксически это выглядит так: (?<name>expr), где name — имя, начинающееся с буквы (как идентификаторы в Ruby). Обратите внимание на сходство этой конструкции с неименованным атомарным подвыражением.

Для чего может понадобиться именованное выражение? Например, для того, чтобы сослаться на него внутри обратной ссылки. Ниже приведен пример простого регулярного выражения для сопоставления с повторяющимся словом (см. также раздел 3.14.6):

re1 = /s+(w+)s+1s+/
str = "Now is the the time for all..."
re1.match(str).to_a # ["the the","the"]

Здесь мы запомнили слово, а затем сослались на него по номеру 1. Примерно так же можно пользоваться ссылками на именованные выражения. При первом обнаружении подвыражения ему присваивается имя, а в обратной ссылке употребляется символ k, за которым следует это имя (всегда в угловых скобках):

re2 = /s+(?<anyword>w+)s+k<anyword>s+/

Второй вариант длиннее, зато понятнее. (Имейте в виду, что в одном и том же регулярном выражении нельзя использовать и именованные, и нумерованные обратные ссылки.) Если нравится, пользуйтесь!

В Ruby уже давно можно включать обратные ссылки в строки, передаваемые методам sub и gsub. Раньше с этой целью допускалось лишь использование нумерованных ссылок, но в самых последних версиях именованные тоже разрешены:

str = "I breathe when I sleep"
# Нумерованные соответствия...
r1 = /I (w+) when I (w+)/
s1 = str.sub(r1,' I 2 when I 1')
# Именованные соответствия...
r1 = /I (?<verb1>w+) when I (?<verb2>w+)/
s2 = str.sub(r2,'I k<verb2> when I k<verb1>')
Puts s1 # I sleep when I breathe
Puts s2 # I sleep when I breathe

Еще одно возможное применение именованных выражений — повторное употребление выражения. В таком случае перед именем ставится символ g (а не k). Определим, например, образец spaces так, чтобы можно было использовать его многократно. Тогда последнее выражение примет вид:

re3 = /(?<spaces>s+)(?<anyword>w+)g<spaces>k<anyword>g<spaces>/

Обратите внимание, что этот образец многократно употребляется с помощью маркера g. Особенно удобна такая возможность в рекурсивных регулярных выражениях, но это тема следующего раздела.

Нотацией g<1> можно пользоваться и тогда, когда именованных подвыражений нет. Тогда запомненное ранее подвыражение вызывается по номеру, а не по имени.

И последнее замечание об именованных соответствиях. В самых последних версиях Ruby имя (в виде строки или символа) может передаваться методу MatchData в качестве индекса, например:

str = "My hovercraft is full of eels"
reg = /My (?<noun>w+) is (?<predicate>.*)/
m = reg.match(str)
puts m[:noun] # hovercraft
puts m["predicate"] # full of eels
puts m[1] # то же, что m[:noun] или m["noun"]

Как видите, обычные индексы тоже не запрещены. Обсуждается возможность добавить в объект MatchData и синглетные методы.

puts m.noun
puts m.predicate

Но во время работы над книгой это еще не было реализовано.

Оглавление книги


Генерация: 1.627. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз