在同一行上查找和编辑多个正则表达式匹配

时间:2016-06-30 19:34:49

标签: ruby regex gollum-wiki

我想在(gollum)wiki页面中为关键短语添加markdown,该页面将链接到表单中的相关wiki页面:

This is the key phrase.

变为

This is the [[key phrase|Glossary#key phrase]].

我有一个关键短语列表,例如:

keywords = ["golden retriever", "pomeranian", "cat"]

一份文件:

Sue has 1 golden retriever. John has two cats.
Jennifer has one pomeranian. Joe has three pomeranians.

我想迭代每一行,找到每个关键字的每个匹配(不是链接)。我目前的尝试看起来像这样:

File.foreach(target_file) do |line|
    glosses.each do |gloss|
        len = gloss.length
        # Create the regex. Avoid anything that starts with [
        # or (, ends with ] or ), and ignore case.
        re = /(?<![\[\(])#{gloss}(?![\]\)])/i
        # Find every instance of this gloss on this line.
        positions = line.enum_for(:scan, re).map {Regexp.last_match.begin(0) }
        positions.each do |pos|
            line.insert(pos, "[[")
            # +2 because we just inserted 2 ahead.
            line.insert(pos+len+2, "|#{page}\##{gloss}]]")
        end
    end
    puts line
end

但是,如果同一行上的同一个关键短语有两个匹配项,则会遇到问题。因为我在线上插入东西,所以我在第一个匹配后找到的位置不准确。我知道我每次都可以根据插入的大小进行调整,但是因为我的插入对于每种光泽都有不同的大小,所以它似乎是最强力,最笨拙的解决方案。

是否有解决方案允许我同时在同一行上进行多次插入,而不是每次都进行多次任意调整?

1 个答案:

答案 0 :(得分:2)

在看了@ BryceDrew的在线python版本之后,我意识到ruby可能也有办法填补这场比赛。我现在有一个更简洁,更快速的解决方案。

首先,我需要制作我的光泽的正则表达式:

glosses.push(/(?<![\[\(])#{gloss}(?![\]\)])/i)

注意:大多数正则表达式都是前瞻和后面的断言,以防止捕获已经是链接的短语。

然后,我需要制作所有这些union

re = Regexp.union(glosses)

之后,就像在每一行上执行gsub一样简单,并填写我的匹配项:

File.foreach(target_file) do |line|
  line = line.gsub(re) {|match| "[[#{match}|Glossary##{match.downcase}]]"}
  puts line
end