Bug #3147
closedgsub evaluates the passed in replacement string making results unpredictable when replacement string is dynamically generated
Description
=begin
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"
=end
Updated by wwalker (Wayne Walker) over 14 years ago
=begin
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]
=end
Updated by shyouhei (Shyouhei Urabe) over 14 years ago
- Status changed from Open to Rejected
=begin
"\\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.
=end
Updated by wwalker (Wayne Walker) over 14 years ago
=begin
This at least needs to be documented clearly in gsub. Strings are normally only evaluated once, not twice.
=end
Updated by murphy (Kornelius Kalnbach) over 14 years ago
=begin
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.
[murphy]
=end