简体   繁体   中英

regular expression in gsub with \1 unexpected behaviour

This example behaves as expected:

"cl. 23".gsub(/([0-9]+)/, '|' + '\1'.to_s + '|')
# => "cl. |23|"

but this doesn't:

"cl. 23".gsub(/([0-9]+)/, '|' + '\1'.to_i.to_s + '|')
# => "cl. |0|"

Why does the expression '\\1'.to_i.to_s return "0" ?

for more clarity, my aim is to be able to use a condition in gsub using \\1:

 "cl. 23".gsub(/([0-9]+)/, '|' + ('\1'.to_i > 36 ? 'g' : 'service' ) + '|')

'\\1' is "\\\\1" : \\ + 1 .

It is not a valid numerical representation. (because of leading \\ ); String#to_i returns 0 for such string.

BTW, if you want surround the number with | , you don't need to_i , to_s . Just use |\\1| as replacement string.

"cl. 23".gsub(/([0-9]+)/, '|\1|')
# => "cl. |23|"

In Ruby (or in most other programming languages), all arguments are evaluated before the method call that uses them.

With the first example, the arguments are first evaluated, and becomes:

gsub(/([0-9]+)/, '|' + '\1'.to_s + '|')
# => gsub(/([0-9]+)/, '|' + '\1' + '|')
# => gsub(/([0-9]+)/, '|\1|')

On the other hand, with the second example, the arguments are evaluated and becomes:

gsub(/([0-9]+)/, '|' + '\1'.to_i.to_s + '|')
# => gsub(/([0-9]+)/, '|' + 0.to_s + '|')
# => gsub(/([0-9]+)/, '|' + '0' + '|')
# => gsub(/([0-9]+)/, '|0|')

Again, all arguments are evaluated before the method call that uses them . From this, it follows that, if you want the replacement string of gsub to depend on the match, you cannot put the replacement formula in the argument; you have to use a block. Looks like this is what you wanted:

"cl. 23".gsub(/([0-9]+)/){'|' + ($1.to_i > 36 ? 'g' : 'service' ) + '|'}

which works but actually is not smart. A better way is

"cl. 23".gsub(/\d+/){|s| "|#{s.to_i > 36 ? "g" : "service"}|"}

It seems you are expecting the method to_i to be called on the group matched by the regexp. Actually it is called on the string '\\1' .

String#to_i returns 0 because, as the documentation says:

If there is not a valid number at the start of str, 0 is returned.

irb> '\1'.to_i
# => 0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM