4

I want to replace all occurrences of a single quote (') with backslash single quote (\'). I tried doing this with gsub, but I'm getting partial string duplication:

a = "abc 'def' ghi"
a.gsub("'", "\\'")
# => "abc def' ghidef ghi ghi"

Can someone explain why this happens and what a solution to this is?

sawa
  • 165,429
  • 45
  • 277
  • 381
11th Hour Worker
  • 337
  • 3
  • 14
  • 1
    https://stackoverflow.com/questions/1542214/weird-backslash-substitution-in-ruby should answer your question – bjhaid Jan 22 '16 at 01:36
  • Thanks for the quick reply bjhaid! That answers my question. You should have posted it as answer. Then I could've upvoted you. – 11th Hour Worker Jan 22 '16 at 01:38

3 Answers3

3

It happens because "\\'" has a special meaning when it occurs as the replacement argument of gsub, namely it means the post-match substring.

To do what you want, you can use a block:

a.gsub("'"){"\\'"}
# => "abc \\'def\\' ghi"

Notice that the backslash is escaped in the string inspection, so it appears as \\.

sawa
  • 165,429
  • 45
  • 277
  • 381
  • 1
    You don't need to use the block form; you just need to prepend ``\'`` with another ``\``, which in double-quotes looks like `"\\\\'"`: `a.gsub("'", "\\\\'")` – Jordan Running Jan 22 '16 at 01:48
3

Your "\\'" actually represents a literal \' because of the backslash escaping the next backslash. And that literal \' in Ruby regex is actually a special variable that interpolates to the part of the string that follows the matched portion. So here's what's happening.

abc 'def' ghi
    ^

The caret points to the first match, '. Replace it with everything to its right, i.e. def' ghi.

abc def' ghidef' ghi
    ++++++++

Now find the next match:

abc def' ghidef' ghi
               ^

Once again, replace the ' with everything to its right, i.e. ghi.

abc def' ghidef ghi ghi
               ++++
Andrew Cheong
  • 29,362
  • 15
  • 90
  • 145
2

It's possible you just need a higher dose of escaping:

a.gsub(/'/, "\\\\'" )

Result:

abc \'def\' ghi

l'L'l
  • 44,951
  • 10
  • 95
  • 146