144

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

6 Answers 6

226

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"
Sign up to request clarification or add additional context in comments.

7 Comments

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.
|
40

\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.

Comments

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

2 Comments

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

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"

Comments

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

Comments

1

$ 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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.