Bug #3147

gsub evaluates the passed in replacement string making results unpredictable when replacement string is dynamically generated

Added by wwalker (Wayne Walker) almost 11 years ago. Updated over 9 years ago.

ruby -v:
ruby 1.8.6 (2009-08-04 patchlevel 383) [i386-linux]


after the interpreter evaluates the replacement string (if it's a literal in "" or ''), gsub further evaluates it during execution changing the effective replacement string.

irb(main):016:0> a = 'Y'
=> "Y"
irb(main):017:0> b = 'Z\1'
=> "Z\1"
irb(main):018:0> c = '\\1'
=> "\\1"
irb(main):019:0> a.gsub(/(Y)/, b)
=> "ZY"
irb(main):020:0> a.gsub(/(Y)/, c)
=> "\1"

The last result is expected to be "\Y"


Updated by wwalker (Wayne Walker) almost 11 years ago

This bug also exists in :

jruby 1.3.1 (ruby 1.8.6p287) (2009-06-15 2fd6c3d)
ruby 1.9.1p376 (2009-12-07 revision 26041) [i686-linux]


Updated by shyouhei (Shyouhei Urabe) almost 11 years ago

  • Status changed from Open to Rejected

"\\1", backslash-backslash-one, is a backslash-escaped backslash plus literal 1.
If what you want to get "\Y" you need another backslash to escape 1 i.e. "\\\1",
backslash-backslash backslash-one.


Updated by wwalker (Wayne Walker) almost 11 years ago

This at least needs to be documented clearly in gsub. Strings are normally only evaluated once, not twice.



Updated by murphy (Kornelius Kalnbach) almost 11 years ago

I use the pattern str.gsub(pattern) { replacement } when I'm not sure
about the replacement. In this case:

'Y'.gsub(/(Y)/) { '\' + $1 }

This specific example could also be written as:

'Y'.gsub(/(?=Y)/, '\')

Both avoid the backslash issue.

Escaping rules in replacement strings are indeed confusing. If you want
a single backslash in the output, you need four of them in the literal.

Adding Wayne's examples to the documentation would certainly help to
understand this.



Also available in: Atom PDF