2

How to convert a string with special characters escaped to the actual special chars?

For example, if I have this:

s = "hello\\nworld"

The output of puts is naturally this:

> puts s
hello\nworld

But how do I transform it into this?

hello
world

In other words, is there any function to unescape backslashed characters?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
rigon
  • 1,310
  • 4
  • 15
  • 37

3 Answers3

2

Your best bet is to do some string replacements.

s = "hello\\nworld"
puts s.gsub("\\n", "\n")
# >> hello
# >> world

The downside of this approach is that you have to explicitly list/process all special chars you need to unescape.

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • 1
    I guess that table substitutions in double quoted will be helpful - [table](https://i.stack.imgur.com/83EBc.png) – Dmitry Cat Mar 23 '17 at 20:26
  • The approach is something like that, but I really want to avoid that. That makes an ugly code... – rigon Mar 23 '17 at 20:29
  • @rigon: yeah well, you're free to prefer elegant `eval`. But I wouldn't recommend that. Out of curiousity, what exactly do you think is "ugly" about this piece of code? – Sergio Tulentsev Mar 23 '17 at 20:31
  • Because of this: https://github.com/ruby/ruby/blob/trunk/doc/syntax/literals.rdoc#strings To cover all the possibilities is pretty complex. And I agree with you, the `eval` approach is a way worse. Ruby doesn't something like this `s.unescape_special_chars`? – rigon Mar 23 '17 at 20:38
  • 1
    @rigon This really *doesn't* make for ugly code. You should be putting your logic in `escape` and `unescape` methods, or using such already written methods as provide by other libraries – user229044 Mar 23 '17 at 20:42
  • @meagar Which libraries does that? – rigon Mar 23 '17 at 20:43
  • @rigon: as meagar says. Also instead of chaining gsubs (`gsub(...).gsub(...).gsub(...)`), you can put all substitutions in a hash/table and do a clever `reduce` on it. – Sergio Tulentsev Mar 23 '17 at 20:44
  • 2
    @rigon See https://stackoverflow.com/questions/9683985/unescaping-special-character-sequences-in-ruby-strings – user229044 Mar 23 '17 at 20:44
0

You interpolate \ by \\ , use one backslash instead of two:

s = "hello\nworld"
puts s 
#=> hello
    world
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Dmitry Cat
  • 475
  • 3
  • 11
-3

If your string is from a trusted source, you can use eval:

s = "hello\\nworld"    
eval("\"#{s}\"") # => "hello\nworld"

Note that this allows arbitrary code execution:

s = "\"; loop { }; \""
eval("\"#{s}\"") # => infinite loop

Also this doesn't work for input like s = "\"".

Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • what will happen if s = "User.delete_all" for example or "while true puts 'kek'"? – Dmitry Cat Mar 23 '17 at 20:09
  • @DmitryCat It returns the string as expected? (Note the quotes.) – Emil Laine Mar 23 '17 at 20:11
  • 1
    yes, but s = "\"" returns error – Dmitry Cat Mar 23 '17 at 20:14
  • 1
    This is really bad, and the fact that you think wrapping it in quotes is somehow effective just demonstrates how problematic `eval` actually is. You have done absolutely nothing to prevent arbitrary code execution. This does **not** "work against malicious input". – user229044 Mar 23 '17 at 20:32
  • 4
    @tuple_cat `'#{User.destory_all}'`, or `'"; User.destroy_all; "'` or any number of a million others. – user229044 Mar 23 '17 at 20:34