用捕获的正则表达式模式替换Ruby字符串

140

我在尝试将这段代码翻译成 Ruby,但遇到了问题。

以下是一段 JavaScript 代码,它完全符合我的需求:

function get_code(str){
    return str.replace(/^(Z_.*): .*/,"$1")​​​​​​​​​​​​​​​​​​​​​​​​​​​;
}

我已经尝试过gsubsubreplace,但似乎都不能达到我的预期效果。

下面是我尝试过的一些例子:

"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/) { |capture| capture }
"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, "$1")
"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, "#{$1}")
"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, "\1")
"Z_sdsd: sdsd".gsub(/(.).*/) { |capture| capture }
6个回答

219

尝试使用'\1'进行替换(单引号很重要,否则需要转义\):

"foo".gsub(/(o+)/, '\1\1\1')
#=> "foooooo"

但是,既然您只对捕获组感兴趣,请注意您可以使用正则表达式索引字符串:

"foo"[/oo/]
#=> "oo"
"Z_123: foobar"[/^Z_.*(?=:)/]
#=> "Z_123"

80
请注意,这仅在替换字符串位于单引号内时才起作用。我浪费了5分钟来弄清楚这一点。 - Vicky Chijwani
7
@MarkThomas - 往往我们会先尝试最高票/被采纳的答案,而不是完整地阅读所有答案。这似乎通常是解决问题最有效的方法。给Vicky一个喘息的机会吧! :) - Josh M.
1
@VickyChijwani 的评论很好,但也请注意,在使用 Ruby inline(在命令行上使用 -e)时,更有可能看到双引号printf "Punkinhead the name" | ruby -ne 'puts gsub /.*(the name)/, "Jonathans \\1"'因为提供给 -e 的表达式通常会用单引号括起来。 - Jonathan Komar
1
@JagdeepSingh,默认情况下,它会替换所有出现的内容。 - Iulian Onofrei
2
@VickyChijwani 当你想使用双引号时,可以写成"\\1"而不是'\1'。然后就可以像这样使用"Z_123_2018".gsub(/\A(Z_\d+_)(\d{4})\z/, "\\1#{$2.to_i+1}") → "Z_123_2019" - Sandro L
显示剩余2条评论

39

需要在双引号中对\1进行转义。因此,您需要使用下列任一方式:

\\1 或者 \\\1
"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, "\\1")
或者
"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, '\1')

请查看gsub的文档,其中写道:"如果它是双引号字符串,则两个反向引用都必须在前面加上一个额外的反斜杠。"

话虽如此,如果您只想要匹配结果,可以执行以下操作:

"Z_sdsd: sdsd".scan(/^Z_.*(?=:)/)
或者
"Z_sdsd: sdsd"[/^Z_.*(?=:)/]

请注意,(?=:)是一个非捕获组,这样:就不会出现在你的匹配结果中。


20
 "foobar".gsub(/(o+)/){|s|s+'ball'}
 #=> "fooballbar"

5
不知道我可以做到那个。太棒了! - vreen
那个块非常方便! - RaphaMex

5
如果您需要使用正则表达式来过滤一些结果,并且然后仅使用捕获组,您可以执行以下操作:
str = "Leesburg, Virginia  20176"
state_regex = Regexp.new(/,\s*([A-Za-z]{2,})\s*\d{5,}/)
# looks for the comma, possible whitespace, captures alpha,
# looks for possible whitespace, looks for zip

> str[state_regex]
=> ", Virginia  20176"

> str[state_regex, 1] # use the capture group
=> "Virginia"

2
def get_code(str)
  str.sub(/^(Z_.*): .*/, '\1')
end
get_code('Z_foo: bar!') # => "Z_foo"

1

$ 变量仅被设置为匹配块中的内容:

"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/) { "#{ $1.strip }" }

这也是调用匹配方法的唯一方式。这不会改变匹配,只会剥离"\1"(不改变其本身):
"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, "\\1".strip)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接