Итак, как только я понял, что мне действительно нужен парсер регулярных выражений, все стало на свои места. Я обнаружил этот проект:
, который может генерировать строки, которые соответствуют регулярному выражению. Он определяет грамматику регулярного выражения, используя http://treetop.rubyforge.org/. К сожалению, определяемая им грамматика неполна, хотя и полезна во многих случаях.
Я также наткнулся на https://github.com/mjijackson/citrus,, который выполняет ту же работу, что и Treetop.
Затем я нашел этот умопомрачительный камень:
, который определяет полную грамматику регулярного выражения и анализирует регулярное выражение в доступном для просмотра дереве. Затем я смог пройтись по дереву и выбрать нужные ему части дерева (группы захвата).
К сожалению, в моей вилке была исправлена небольшая ошибка: https://github.com/LaunchThing/regexp_parser.
Вот мой патч для Regexp, который использует фиксированный гем:
class Regexp
def parse
Regexp::Parser.parse(self.to_s, 'ruby/1.9')
end
def walk(e = self.parse, depth = 0, &block)
block.call(e, depth)
unless e.expressions.empty?
e.each do |s|
walk(s, depth+1, &block)
end
end
end
def capture_groups
capture_groups = []
walk do |e, depth|
capture_groups << e.to_s if Regexp::Expression::Group::Capture === e
end
capture_groups
end
end
Затем я могу использовать это в своем приложении, чтобы сделать замены в моей строке - конечной цели - по следующим направлениям:
from = /^\/search\/(.*)$/
to = '/buy/$1'
to_as_regexp = to.dup
# I should probably make this gsub tighter
from.capture_groups.each_with_index do |capture, idx|
to_as_regexp.gsub!("$#{idx+1}", capture)
end
to_as_regexp = /^#{to_as_regexp}$/
# to_as_regexp = /^\/buy\/(.*)$/
Надеюсь, это поможет кому-то еще.