4

I am not getting why

puts("whit'e bread".gsub("'","\\\'"))

is giving result as

white breade bread

I was hoping end result should be

whit\'e bread
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
Good Vibes
  • 163
  • 2
  • 12

1 Answers1

4

The documentation of String#sub explains:

If replacement is a String that looks like a pattern's capture group but is actually not a pattern capture group e.g. "\'", then it will have to be preceded by two backslashes like so "\\'".

But $' is a global variable whose meaning is "The string to the right of the last successful match." and \' in a replacement string has the same meaning.

Now, back to your replacement string, let's remember that in string literals, the backslash (\) is a special character that introduces an escape sequence. In order to represent itself, the backslash must be represented as \\.

Now everything is clear. The replacement string "\\\'" represents a backslash (\\) followed by the escape sequence \' that represents a single quote character (').
(In double quoted string literals, there is no need to escape the single quote characters but the backslash in front of them doesn't change the result; in single quote string literals it is required to use the escape sequence \' to encode a single quote character, otherwise it is the marker of the end of string.)

By combining all said above:

"whit'e bread".gsub("'","\\\'")

replaces the single quote with \' which is e bread (the string to the right of the last successful match) and the result is white breade bread. (The replacement string is displayed in bold letters.)

In order to get the expected result you have to use \\' as the replacement string. The correct way to write it in code as a string literal is "\\\\'". The code becomes:

"whit'e bread".gsub("'","\\\\'")

and it produces the expected result.

Update:

The documentation of String#gsub in Ruby 2.7.0 is more descriptive and clearly says:

Similarly, \&, \', \`, and + correspond to special variables, $&, $', $`, and $+, respectively. (See regexp.rdoc for details.)

Thanks to @sergio-tulentsev for the links he used in his answer.

axiac
  • 68,258
  • 9
  • 99
  • 134
  • Damn, why didn't I see your answer. What a waste of time :) – Sergio Tulentsev Jan 04 '20 at 17:35
  • 1
    We probably were working on our answers on the same time. We both started when there was no answer posted, I probably finished several minutes before you, while you were still digging into the documentation. The documentation of 2.7.0 explains it better than the older one I used. – axiac Jan 04 '20 at 18:04
  • 2
    You can also use the block form of `gsub` to avoid some of the backslashes: `"whit'e bread".gsub("'") { |m| '\\' + m }`. – mu is too short Jan 04 '20 at 18:49
  • @Sergio Tulentsev can you please explain with pattern \\\', here \' from pattern replaces string to the right. But then what about \\ from a pattern where does it go – Good Vibes Jan 04 '20 at 19:19
  • @GoodVibes: try `puts "\\\'"`, you'll see. – Sergio Tulentsev Jan 04 '20 at 19:26
  • 1
    @GoodVibes don't confuse a piece of text (e.g. `\'`) with its representation as a string in the code (`"\\'"` or `'\\\''`). As I explained in the answer, `"\\\'"` is the same as `"\\'"` with an extra ``\`` that doesn't change its meaning. – axiac Jan 04 '20 at 20:03