lib/regexp-examples/backreferences.rb in regexp-examples-1.1.3 vs lib/regexp-examples/backreferences.rb in regexp-examples-1.1.4

- old
+ new

@@ -1,37 +1,53 @@ module RegexpExamples + # A helper class to fill-in backrefences AFTER the example(s) have been generated. + # In a nutshell, this works by doing the following: + # * Given a regex that contains a capute group and backreference, e.g. `/(a|b) \1/` + # * After generating examples, the backreference is tored as a placeholder: + # `["a __1__", "b __1__"]` + # * This class is used to fill in each placeholder accordingly: + # `["a a", "b b"]` + # * Also, beware of octal groups and cases where the backref invalidates the example!! class BackReferenceReplacer - BackrefNotFound = Class.new(StandardError) + # Named capture groups can only contain alphanumeric chars, and hyphens + PLACEHOLDER_REGEX = Regexp.new( + RegexpExamples::BackReferenceGroup::PLACEHOLDER_FORMAT % '([a-zA-Z0-9-]+)' + ) def substitute_backreferences(full_examples) full_examples.map do |full_example| - begin - while full_example.match(/__(\w+?)__/) - full_example.sub!(/__(\w+?)__/, find_backref_for(full_example, Regexp.last_match(1))) - end - full_example - rescue BackrefNotFound - # For instance, one "full example" from /(a|(b)) \2/: "a __2__" - # should be rejected because the backref (\2) does not exist - nil + # For instance, one "full example" from /(a|(b)) \2/: "a __2__" + # should be rejected because the backref (\2) does not exist + catch(:backref_not_found) do + substitute_backrefs_one_at_a_time(full_example) end end.compact end private + def substitute_backrefs_one_at_a_time(full_example) + while full_example.match(PLACEHOLDER_REGEX) + full_example.sub!( + PLACEHOLDER_REGEX, + find_backref_for(full_example, Regexp.last_match(1)) + ) + end + full_example + end + def find_backref_for(full_example, group_id) full_example.all_subgroups.detect do |subgroup| subgroup.group_id == group_id end || octal_char_for(group_id) end def octal_char_for(octal_chars) - # For octal characters in the range \10 - \177 - if octal_chars =~ /\A[01]?[0-7]{1,2}\z/ && octal_chars.to_i >= 10 + # For octal characters in the range \00 - \177 + if octal_chars =~ /\A[01]?[0-7]{1,2}\z/ && octal_chars.length > 1 Integer(octal_chars, 8).chr else - fail(BackrefNotFound) + throw :backref_not_found end end end end