Программирование на языке Ruby - Страница 48
Ознакомительная версия. Доступно 54 страниц из 266.</body>
EOF
pattern = /(?:^| # Начало или...
(?<=>) # текст после '>'
)
([^<]*) # И все символы, кроме '<' (запомнены).
/x
puts text.gsub(pattern) {|s| s.upcase }
# Вывод:
# <body> <h1>THIS IS A HEADING</h1>
# <p>THIS IS A PARAGRAPH WITH SOME
# <i>ITALICS</i> AND SOME <b>BOLDFACE</b>
# IN IT...</p>
# </body>
3.13.5. Еще о кванторах
Мы уже встречались с атомарными подвыражениями в «классической» библиотеке регулярных выражений в Ruby. Они выделяются с помощью нотации (
?>...
Oniguruma предлагает еще один способ выразить собственническую природу — с помощью квантора
+
+
?
??
+?
*?
Применение
+
r1 = /x*+/ # То же, что /(?>x*)/
r2 = /x++/ # То же, что /(?>x+)/
r3 = /x?+/ # То же, что /(?>x?)/
По техническим причинам Ruby не считает конструкцию
{n,m}+
Понятно, что новый квантор — не более чем удобное обозначение, никакой новой функциональности он не несет.
3.13.6. Именованные соответствия
Специальной формой подвыражения является именованное выражение, которое позволяет присвоить образцу имя (а не просто порядковый номер).
Синтаксически это выглядит так: (
?<name>expr
Для чего может понадобиться именованное выражение? Например, для того, чтобы сослаться на него внутри обратной ссылки. Ниже приведен пример простого регулярного выражения для сопоставления с повторяющимся словом (см. также раздел 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
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
Но во время работы над книгой это еще не было реализовано.
3.13.7. Рекурсия в регулярных выражениях
Возможность повторно обращаться к подвыражению позволяет создавать рекурсивные регулярные выражения. Например, данный код находит любое вложенное выражение с правильно расставленными скобками (спасибо Эндрю Джексону):