gsub部分替换
我想在此表达式中仅替换括号中的组:
my_string.gsub(/(.)*/, 'replace_text')
所以我得到: replace_text
我知道我可以在替换表达式中重复整个MARKER_START
和MARKER_END
块,但我认为应该有一种更简单的方法来执行此操作。
你可以这样做:
my_string.gsub(/(<--MARKER_START-->)(.*)(<--MARKER_END-->)/, '\1replace_text\3')
您可以使用零宽度前瞻和后置断言来实现 。
这个正则表达式应该在ruby 1.9和perl以及许多其他地方工作:
注意:ruby 1.8仅支持先行断言。 你需要前瞻和后视来正确地做到这一点。
s.gsub( /(?<=<--MARKER START-->).*?(?=<--MARKER END-->)/, 'replacement text' )
在ruby 1.8中发生的是?<=
导致它崩溃,因为它不理解后面的断言。 对于那部分,你必须回到使用反向引用 - 比如Greig Hewgill提到的
所以你得到的是
s.gsub( /(<--MARKER START-->).*?(?=<--MARKER END-->)/, '\1replacement text' )
解释第一:
我用(.)*
替换了你的正则表达式中间的(.)*
.*?
- 这不贪心。 如果你没有非贪婪,那么你的正则表达式将尝试尽可能多地匹配 - 如果你在一行上有2个标记,则会出错。 最好通过示例说明:
"One Two Three".gsub( /.*<\/b>/, 'BOLD' ) => "BOLD"
我们真正想要的是:
"One Two Three".gsub( /.*?<\/b>/, 'BOLD' ) => "BOLD Two BOLD"
解释第二:
零宽度前瞻声明听起来像一堆书呆子混乱。
什么“超前断言”实际上意味着“只有匹配,如果我们正在寻找的东西,其次是其他东西。
例如,只匹配一个数字,如果后跟一个数字。
"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-->
是能够说“只匹配,如果我们正在寻找的东西为了这个其他的东西“。 这被称为后视断言,ruby1.8没有出于某种奇怪的原因。
希望有道理:-)
PS:为什么使用先行断言而不仅仅是反向引用? 如果你使用lookahead,你实际上并没有替换<--MARKER-->
位,只替换内容。 如果你使用反向引用,你将取代整个批次。 我不知道这是否会引起很多性能损失,但从编程的角度来看,这似乎是正确的做法,因为我们实际上根本不想更换标记。