3

I'm trying to replace single quotes (') with escaped single quotes (\') in a string in ruby 1.9.3 and 1.8.7.

The exact problem string is "Are you sure you want to delete '%@'". This string should become "Are you sure you want to delete \'%@\'"

Using .gsub!(/\'/,"\'") leads to the following string "Are you sure you want to %@'%@".

Any ideas on what's going on?

Ryan Levick
  • 51
  • 1
  • 4
  • This answer will answer your question on how to escape the string, and why (i.e. that `\'` is a substitution replacement, etc): http://stackoverflow.com/a/2180375/746882 – Frost Nov 19 '12 at 17:00
  • Your expected string is no different than the original, and is hence wrong. What you actually meant is "Are you sure you want to delete \\'%@\\'". – sawa Nov 19 '12 at 17:04

3 Answers3

8

String#gsub in the form gsub(exp,replacement) has odd quirks affecting the replacement string which sometimes require lots of escaping slashes. Ruby users are frequently directed to use the block form instead:

str.gsub(/'/){ "\\'" }

If you want to do away with escaping altogether, consider using an alternate string literal form:

str.gsub(/'/){ %q(\') }

Once you get used to seeing these types of literals, using them to avoid escape sequences can make your code much more readable.

marcus erronius
  • 3,613
  • 1
  • 16
  • 32
1

\' in a substitution replacement string means "The portion of the original string after the match". So str.gsub!(/\'/,"\\'") replaces the ' character with everything after it - which is what you've noticed.

You need to further escape the backslash in the replacement. .gsub(/'/,"\\\\'") works in my irb console:

irb(main):059:0> puts a.gsub(/'/,"\\\\'")
Are you sure you want to delete \'%@\'
Chowlett
  • 45,935
  • 20
  • 116
  • 150
  • As an addition to this answer, there's actually no need to escape the single quote character. Just doing `gsub(/'/, ...` will actually do the same thing. You'll still need the quadruple backslashes though. – Frost Nov 19 '12 at 17:03
  • The reason I want "\'" literally is that this is a parser, and I'll be sending these strings on for use in XML, Resx and JSON files. Therefore the \' needs to literally be \' so that the other languages can parse the string correctly. – Ryan Levick Nov 19 '12 at 17:58
  • Then you need the four-backslash version. Remember that, since `\ ` is special to Ruby, Ruby needs to know you want it as a literal. So you give `\\\\'` in the replacement to make `\\'` in the string, which is a string containing _one literal_ `\ `. The `puts` result is a good indication your string has a real backslash in it. Note too that `"'%@'".gsub(/\'/,"\\\\'").length` gives 6 - the length of `\'%@\'` – Chowlett Nov 20 '12 at 08:49
  • No worries. Remember you can mark this answer as helpful (click the up arrow), and/or accept it (click the green check mark). – Chowlett Nov 20 '12 at 10:39
0

You need to escape the backslash. What about this?

"Are you sure you want to delete '%@'".gsub(/(?=')/, "\\")
# => "Are you sure you want to delete \\'%@\\'"

The above should be what you want. Your expected result is wrong. There is no way to literally see a single backslash when it means literally a backslash.

sawa
  • 165,429
  • 45
  • 277
  • 381