在同一行中查找和编辑多个正则表达式匹配项
Finding and Editing Multiple Regex Matches on the Same Line
我想将 markdown 添加到 (gollum) wiki 页面中的关键短语,这将 link 以以下形式添加到相关的 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.
我想遍历每一行并找到每个关键字的每个匹配项(还不是 link)。我目前的尝试是这样的:
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
但是,如果同一行上的同一关键词有两个匹配项,这将 运行 变成一个问题。因为我将东西插入到行中,所以我为每个匹配项找到的位置在第一个匹配项之后就不准确了。我知道我每次都可以调整插入的大小,但是,因为我的插入对于每种光泽来说都是不同的大小,这似乎是最蛮力、最老套的解决方案。
有没有解决方案可以让我在同一时间在同一行上进行多次插入,而不需要每次都任意调整几次?
看了@BryceDrew 的在线python 版本后,我意识到ruby 可能也有填充匹配的方法。我现在有了一个更简洁、更快速的解决方案。
首先,我需要为我的注解制作正则表达式:
glosses.push(/(?<![\[\(])#{gloss}(?![\]\)])/i)
注意:该正则表达式的大部分是前瞻和后视断言,以防止捕捉到已经属于 link.
的短语
然后,我需要对所有这些进行 union:
re = Regexp.union(glosses)
之后,只需在每一行上执行 gsub,然后填写我的匹配项:
File.foreach(target_file) do |line|
line = line.gsub(re) {|match| "[[#{match}|Glossary##{match.downcase}]]"}
puts line
end
我想将 markdown 添加到 (gollum) wiki 页面中的关键短语,这将 link 以以下形式添加到相关的 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.
我想遍历每一行并找到每个关键字的每个匹配项(还不是 link)。我目前的尝试是这样的:
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
但是,如果同一行上的同一关键词有两个匹配项,这将 运行 变成一个问题。因为我将东西插入到行中,所以我为每个匹配项找到的位置在第一个匹配项之后就不准确了。我知道我每次都可以调整插入的大小,但是,因为我的插入对于每种光泽来说都是不同的大小,这似乎是最蛮力、最老套的解决方案。
有没有解决方案可以让我在同一时间在同一行上进行多次插入,而不需要每次都任意调整几次?
看了@BryceDrew 的在线python 版本后,我意识到ruby 可能也有填充匹配的方法。我现在有了一个更简洁、更快速的解决方案。
首先,我需要为我的注解制作正则表达式:
glosses.push(/(?<![\[\(])#{gloss}(?![\]\)])/i)
注意:该正则表达式的大部分是前瞻和后视断言,以防止捕捉到已经属于 link.
的短语然后,我需要对所有这些进行 union:
re = Regexp.union(glosses)
之后,只需在每一行上执行 gsub,然后填写我的匹配项:
File.foreach(target_file) do |line|
line = line.gsub(re) {|match| "[[#{match}|Glossary##{match.downcase}]]"}
puts line
end