我只想替换此表达式中括号中的组:
my_string.gsub(/<--MARKER_START-->(.)*<--MARKER_END-->/, 'replace_text')所以我得到了:<--MARKER_START-->replace_text<--MARKER_END-->
我知道我可以在替换表达式中重复整个MARKER_START和MARKER_END块,但我认为应该有一种更简单的方法来做到这一点。
发布于 2008-09-23 02:56:04
你可以这样做:
my_string.gsub(/(<--MARKER_START-->)(.*)(<--MARKER_END-->)/, '\1replace_text\3')发布于 2008-09-23 03:31:55
你可以用zero width look-ahead and look-behind assertions做到这一点。
这个正则表达式应该可以在Ruby1.9、perl和许多其他地方工作:
注意: ruby 1.8只支持先行断言。要正确地做到这一点,您需要同时向前看和向后看。
s.gsub( /(?<=<--MARKER START-->).*?(?=<--MARKER END-->)/, 'replacement text' )在Ruby1.8中发生的事情是?<=导致它崩溃,因为它不理解向后看断言。对于这一部分,您必须退回到使用类似于反向引用的Greig Hewgill mentions
所以你得到的是
s.gsub( /(<--MARKER START-->).*?(?=<--MARKER END-->)/, '\1replacement text' )第一个解释:
我已经用.*?替换了正则表达式中间的(.)* -这是非贪婪的。如果您没有非贪婪,那么您的正则表达式将尝试尽可能多地匹配-如果一行上有两个标记,则会出错。下面的例子最能说明这一点:
"<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"第二个解释:
零宽度前瞻断言听起来像一大堆书呆子般的困惑。
“先行断言”的实际含义是“只有匹配,如果我们正在寻找的东西,后面是这个其他东西。
例如,如果数字后面跟一个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:为什么要使用先行断言而不是仅仅是反向引用?如果使用lookahead,实际上并不是替换<--MARKER-->位,而是替换内容。如果你使用反向引用,你就会替换掉整个代码。我不知道这是否会对性能造成很大的影响,但从编程的角度来看,这似乎是正确的做法,因为我们实际上根本不想替换标记。
https://stackoverflow.com/questions/118839
复制相似问题