您可以使用zero width look-ahead and look-behind assertions 来完成。
这个正则表达式应该可以在 ruby 1.9 和 perl 以及许多其他地方工作:
注意:ruby 1.8 仅支持前瞻断言。您需要前瞻和后瞻才能正确执行此操作。
s.gsub( /(?<=<--MARKER START-->).*?(?=<--MARKER END-->)/, 'replacement text' )
在 ruby 1.8 中发生的是 ?<= 导致它崩溃,因为它不理解后向断言。对于那部分,您必须回退到使用反向引用 - 例如Greig Hewgill mentions
所以你得到的是
s.gsub( /(<--MARKER START-->).*?(?=<--MARKER END-->)/, '\1replacement text' )
解释第一:
我已将您正则表达式中间的 (.)* 替换为 .*? - 这是非贪婪的。
如果您没有非贪婪,那么您的正则表达式将尝试尽可能多地匹配 - 如果您在一行上有 2 个标记,则会出错。最好用例子来说明这一点:
"<b>One</b> Two <b>Three</b>".gsub( /<b>.*<\/b>/, 'BOLD' )
=> "BOLD"
我们真正想要的:
"<b>One</b> Two <b>Three</b>".gsub( /<b>.*?<\/b>/, 'BOLD' )
=> "BOLD Two BOLD"
第二个解释:
零宽度前瞻性断言听起来像是一大堆书呆子的困惑。
“look-ahead-assertion”实际上的意思是“只有匹配,如果我们正在寻找的东西,后面跟着其他东西。
例如,只匹配一个数字,如果它后跟一个 F。
"123F" =~ /\d(?=F)/ # will match the 3, but not the 1 or the 2
“零宽度”的实际含义是“在我们的搜索中考虑‘跟随’,但在进行替换或分组或类似的事情时不要将其视为匹配的一部分。
使用 123F 的相同示例,如果我们不使用前瞻断言,而是这样做:
"123F" =~ /\dF/ # will match 3F, because F is considered part of the match
如您所见,这是检查我们的<--MARKER END--> 的理想选择,但我们需要<--MARKER START--> 能够说“仅匹配,如果我们正在寻找的东西跟随其他东西”。这称为后视断言,由于某种奇怪的原因,ruby 1.8 没有这种断言。
希望这是有道理的:-)
PS:为什么使用前瞻断言而不是反向引用?如果您使用前瞻,您实际上并没有替换 <--MARKER--> 位,只是替换内容。如果您使用反向引用,您将替换整个批次。我不知道这是否会对性能造成很大影响,但从编程的角度来看,这似乎是正确的做法,因为我们实际上根本不想替换标记。