Pregunta

This code all works and produces 11 22 and 2032.

date = '11-22-2032'
mon, day, year = $1, $2, $3 if date =~ /(\d\d)-(\d\d)-(\d\d)/
p mon,day,year

But something like this won't work:

str = "This is a string"
str.gsub!(/(\w+)/, "1#{$1}")
p str => prints all whitespace

Does Ruby evaluates expressions starting from the right (thus the reason why the first example works?) How can I make the second example work (in the same .gsub method to make the word capture enclosed in () available, so I can add 1 before every word)?

¿Fue útil?

Solución

The fact your second example does not work, has nothing to do with the order in which the if is being evaluated.

Instead, use \1 and \2 as interpolation variables.

str = "This is a string"
str.gsub!(/(\w+)/, '1\1')
print str

Also note that "\1" is interpolated, you need '\1'.

Otros consejos

I don't think gsub sets the global vars $1, $2, etc. in a way that can be used in the replacement string (see http://www.ruby-doc.org/core-1.9.3/String.html#method-i-gsub). Instead, use backreferences \1 (since you're including them in a double-quoted string, you need to double-escape as "\\1"):

>> str = "This is a string"
=> "This is a string"
>> str.gsub!(/(\w+)/, "1\\1")
=> "1This 1is 1a 1string"

The reason you can't use $1 this way is because you are passing the string as an arg into the gsub method, which means it, along with the interpolated $1, is evaluated before gsub gets to set and use it. @berkes's answer is one way and probably the best way to avoid that and to get the matched group(s).

But FYI you can also use a block:

str = "This is a string"
str.gsub!(/(\w+)/) {"1#{$1}"}

Because the block is evaluated only when called, which will be after gsub has already performed the match.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top