ChatGPT解决这个技术问题 Extra ChatGPT

Ruby replace string with captured regex pattern

I am having trouble translating this into Ruby.

Here is a piece of JavaScript that does exactly what I want to do:

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

I have tried gsub, sub, and replace but none seem to do what I am expecting.

Here are examples of things I have tried:

"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 }

J
Jake Berger

Try '\1' for the replacement (single quotes are important, otherwise you need to escape the \):

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

But since you only seem to be interested in the capture group, note that you can index a string with a regex:

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

Note that this only works if the replacement string is inside single quotes. I wasted 5 minutes figuring that out.
@MarkThomas - often times we try the top/accepted answer first without reading the entirety of answers. That seems to generally be the most efficient means of fixing a problem. Give Vicky a break! :)
@VickyChijwani Good comment, but also note that when using Ruby inline (on the command line with -e), it is more likely to see double quotes: printf "Punkinhead the name" | ruby -ne 'puts gsub /.*(the name)/, "Jonathans \\1"' because expression provided to -e is usually wrapped in single quotes.
@JagdeepSingh, It, by default, replaces all the occurrences.
@VickyChijwani When youn want to use double quotes you can wirte "\\1" instead of '\1'. Then something like "Z_123_2018".gsub(/\A(Z_\d+_)(\d{4})\z/, "\\1#{$2.to_i+1}") → "Z_123_2019" is possible.
M
Mark Thomas

\1 in double quotes needs to be escaped. So you want either

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

or

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

see the docs on gsub where it says "If it is a double-quoted string, both back-references must be preceded by an additional backslash."

That being said, if you just want the result of the match you can do:

"Z_sdsd: sdsd".scan(/^Z_.*(?=:)/)

or

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

Note that the (?=:) is a non-capturing group so that the : doesn't show up in your match.


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

didn't know I can do that. Nice!
That block is very handy!
g
grumpit

If you need to use a regex to filter some results, and THEN use only the capture group, you can do the following:

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"

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

L
Lisapple

$ variables are only set to matches into the block:

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

This is also the only way to call a method on the match. This will not change the match, only strip "\1" (leaving it unchanged):

"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, "\\1".strip)