module ParallelRegexp class Replacement < Array def initialize(items=[]) super(items.collect { |i| i.is_a?(Substitution) ? i : Substitution.new(i.first, i.last) }) end def append(regexp, replacement) self << Substitution.new(regexp, replacement) end def exec(string) string.gsub to_re do match_data = Regexp.last_match replacement, i = '', 1 each do |sub| if match_data[i] replacement = sub.replacement.call(match_data.to_a[i..-1]) break else i += sub.subexps end end replacement end end def to_re regexps = collect { |i| i.regexp } Regexp.new("(#{regexps.join(')|(')})") end end class Substitution LOOKUP = /\$(\d+)/ BRACKETS = /\(/ ESCAPE = /\\./ attr_reader :regexp, :replacement, :subexps def initialize(regexp, replacement) @regexp = regexp.to_s @replacement = replacement_proc_for(replacement) end private def replacement_proc_for(replacement) @subexps = @regexp.gsub(ESCAPE, '').scan(BRACKETS).length if replacement =~ LOOKUP if replacement =~ /^\$(\d+)$/ index = $1.to_i lambda { |match_data| match_data[index] } else rep_expression = replacement.gsub /\$(\d+)/ do '#{match_data[' + $1 + ']}' end eval "lambda { |match_data| \"#{rep_expression}\" }" end else lambda { |match_data| replacement } end end end end