How to escape slashes in single-quoted strings? - ruby

In Ruby 1.8.6 (2007-09-24 patchlevel 111):
str = '\&123'
puts "abc".gsub("b", str) => ab123c
puts "abc".gsub("b", "#{str}") => ab123c
puts "abc".gsub("b", str.to_s) => ab123c
puts "abc".gsub("b", '\&123') => ab123c
puts "abc".gsub("b", "\&123") => a&123c <--- This I want to achieve using temporary variable
If I change str = '\&123' to str = "\&123" it works fine, but I get str from match function, so I cannot specify it manually within parentheses. Is there any way to change the 'string' to "string" behavior?

maybe there is a simpler way, however the code below works
> str = '\&123'
> puts "abc".gsub("b", str.gsub(/\\&/o, '\\\\\&\2\1'))
> => a\&123c

Simple:
str = '\&123' <-- the result of your match function
str = str.gsub(/\\/, '\\\\')
You may also want to take a look here.

#Valentin
-> I meant that str from match was not taken verbatim. Thus another (simpler) solution appeared, that I was not aware of....
"abc".gsub("b") { str } -> a\&123c

Just remove the backslash:
puts "abc".gsub("b", '&123')
There is no need to protect the ampersand with a backslash inside
single-quoted string literals (unlike double-quoted ones).

Related

Escape line breaks in puts output

In IRB on Ruby 1.8.7, I have a collection of strings I'm working with that have newlines in them. When these newlines are output, I want to explicitly see the \r and \n characters within my strings. Is there some way to tell puts to escape those characters, or a method similar to puts that will do what I want?
Note that directly evaluating each string isn't satisfactory because I want to be able to do something like this:
=> mystrings.each { |str| puts str.magical_method_to_escape_special_chars }
This is\na string in mystrings.
This is another\n\rstring.
And don't want to have to do this:
=> mystrings[0]
"This is\na string in mystrings."
=> mystrings[1]
"This is another\n\rstring."
...
=> mystrings[1000]
"There are a lot of\n\nstrings!"
I can use the string#dump method:
=> mystrings.each { |str| puts str.dump }
This is\na string in mystrings.
This is another\n\rstring.
According to the Ruby documention for String, string#dump
Produces a version of str with all nonprinting characters replaced by
\nnn notation and all special characters escaped.
1.8.7 :001 > s = "hi\nthere"
=> "hi\nthere"
1.8.7 :002 > p s
"hi\nthere"

Eval a string without string interpolation

AKA How do I find an unescaped character sequence with regex?
Given an environment set up with:
#secret = "OH NO!"
$secret = "OH NO!"
##secret = "OH NO!"
and given string read in from a file that looks like this:
some_str = '"\"#{:NOT&&:very}\" bad. \u262E\n##secret \\#$secret \\\\###secret"'
I want to evaluate this as a Ruby string, but without interpolation. Thus, the result should be:
puts safe_eval(some_str)
#=> "#{:NOT&&:very}" bad. ☮
#=> ##secret #$secret \###secret
By contrast, the eval-only solution produces
puts eval(some_str)
#=> "very" bad. ☮
#=> OH NO! #$secret \OH NO!
At first I tried:
def safe_eval(str)
eval str.gsub(/#(?=[{#$])/,'\\#')
end
but this fails in the malicious middle case above, producing:
#=> "#{:NOT&&:very}" bad. ☮
#=> ##secret \OH NO! \###secret
You can do this via regex by ensuring that there are an even number of backslashes before the character you want to escape:
def safe_eval(str)
eval str.gsub( /([^\\](?:\\\\)*)#(?=[{#$])/, '\1\#' )
end
…which says:
Find a character that is not a backslash [^\\]
followed by two backslashes (?:\\\\)
repeated zero or more times *
followed by a literal # character
and ensure that after that you can see either a {, #, or $ character.
and replace that with
the non-backslash-maybe-followed-by-even-number-of-backslashes
and then a backslash and then a #
How about not using eval at all? As per this comment in chat, all that's necessary are escaping quotes, newlines, and unicode characters. Here's my solution:
ESCAPE_TABLE = {
/\\n/ => "\n",
/\\"/ => "\"",
}
def expand_escapes(str)
str = str.dup
ESCAPE_TABLE.each {|k, v| str.gsub!(k, v)}
#Deal with Unicode
str.gsub!(/\\u([0-9A-Z]{4})/) {|m| [m[2..5].hex].pack("U") }
str
end
When called on your string the result is (in your variable environment):
"\"\"\#{:NOT&&:very}\" bad. ☮\n\##secret \\\#$secret \\\\\###secret\""
Although I would have preferred not to have to treat unicode specially, it is the only way to do it without eval.

Ruby - How to keep \n when I print out strings

I would like to keep \n when I print out strings in ruby,
Like now, if I use puts or print, \n will end up with a newline:
pry(main)> print "abc\nabc"
abc
abc
is there a way to let ruby print it out like: abc\nabc ?
UPDATE
Sorry that maybe I didn't make it more clear. I am debugging my regexps, so when I output a string, if a \n is displayed as a \n, not a newline, it would be easier for me to check. So #slivu 's answer is exactly what I want. Thanks guys.
i would suggest to use p instead of puts/print:
p "abc\nabc"
=> "abc\nabc"
and in fact with pry you do not need to use any of them, just type your string and enter:
str = "abc\nabc"
=> "abc\nabc"
str
=> "abc\nabc"
In Ruby, strings in a single quote literal, like 'abc\nabc' will not be interpolated.
1.9.3p194 :001 > print 'abc\nabc'
abc\nabc => nil
vs with double quotes
1.9.3p194 :002 > print "abc\nabc"
abc
abc => nil
Because \n is a special keyword, you have to escape it, by adding a backslash before the special keyword (and because of that, backslashes must also be escaped), like so: abs\\nabc. If you wanted to print \\n, you would have to replace it to be abs\\\\n, and so on (two backslashes to display a backslash).
You can also just use single quotes instead of double quotes so that special keywords will not be interpreted. This, IMHO, is bad practice, but if it makes your code look nicer, I guess it's worth it :)
Here are some examples of ways you can escape (sort of like a TL;DR version):
puts 'abc\nabc' # Single quotes ignore special keywords
puts "abc\\nabc" # Escaping a special keyword (preferred technique, IMHO)
p "abc\nabc" # The "p" command does not interpret special keywords
You can also do it like this
puts 'abc\nabc'
Use %q to create a string for example:
str = %q{abc\nklm}
puts str #=> 'abc\nklm'
or
puts %q{abc\nklm}
or use escape character
puts "abc\\nklm"
To print the string: abc\nabc
The coded string must be: abc\\nabc which will not generate a newline.

Is there any string syntax in Ruby that allows interpolation but no escape character?

Is there any single-line string literal syntax in Ruby that allows string interpolation but does not interpret a backslash as an escape character?
I.e.,
Where ruby_var = "foo"
I want to be able to type the equivalent of C:\some\windows\path\#{ruby_var}\path resulting in the string C:\some\windows\path\foo\path without having to escape the backslashes or resort to a multi-line heredoc.
puts "C:\some\windows\path\#{ruby_var}\path"
puts "C:\some\windows\path\path_#{ruby_var}\path"
=> C: omewindowspath#{ruby_var}path
=> C: omewindowspathpath_foopath
puts 'C:\some\windows\path\#{ruby_var}\path'
puts 'C:\some\windows\path\path_#{ruby_var}\path'
=> C:\some\windows\path\#{ruby_var}\path
=> C:\some\windows\path\path_#{ruby_var}\path
puts %{C:\some\windows\path\#{ruby_var}\path}
puts %{C:\some\windows\path\path_#{ruby_var}\path}
=> C: omewindowspath#{ruby_var}path
=> C: omewindowspathpath_foopath
puts %q{C:\some\windows\path\#{ruby_var}\path}
puts %q{C:\some\windows\path\path_#{ruby_var}\path}
=> C:\some\windows\path\#{ruby_var}\path
=> C:\some\windows\path\path_#{ruby_var}\path
ruby_var = "hello"
puts 'C:\some\windows\path\%s\path' % ruby_var
#=>C:\some\windows\path\hello\path
'C:\some\windows\path\%s\path' % ruby_var
#=> 'C:\some\windows\path\foo\path'
I don't think it is possible.
You should consider using forward slashes instead to make it look prettier; I believe the standard ruby libraries in Windows won't care what kind of slashes you use.
There is also:
File.join('C:', 'path', ruby_var)

Replace single quote with backslash single quote

I have a very large string that needs to escape all the single quotes in it, so I can feed it to JavaScript without upsetting it.
I have no control over the external string, so I can't change the source data.
Example:
Cote d'Ivoir -> Cote d\'Ivoir
(the actual string is very long and contains many single quotes)
I'm trying to this by using gsub on the string, but can't get this to work:
a = "Cote d'Ivoir"
a.gsub("'", "\\\'")
but this gives me:
=> "Cote dIvoirIvoir"
I also tried:
a.gsub("'", 92.chr + 39.chr)
but got the same result; I know it's something to do with regular expressions, but I never get those.
The %q delimiters come in handy here:
# %q(a string) is equivalent to a single-quoted string
puts "Cote d'Ivoir".gsub("'", %q(\\\')) #=> Cote d\'Ivoir
The problem is that \' in a gsub replacement means "part of the string after the match".
You're probably best to use either the block syntax:
a = "Cote d'Ivoir"
a.gsub(/'/) {|s| "\\'"}
# => "Cote d\\'Ivoir"
or the Hash syntax:
a.gsub(/'/, {"'" => "\\'"})
There's also the hacky workaround:
a.gsub(/'/, '\#').gsub(/#/, "'")
# prepare a text file containing [ abcd\'efg ]
require "pathname"
backslashed_text = Pathname("/path/to/the/text/file.txt").readlines.first.strip
# puts backslashed_text => abcd\'efg
unslashed_text = "abcd'efg"
unslashed_text.gsub("'", Regexp.escape(%q|\'|)) == backslashed_text # true
# puts unslashed_text.gsub("'", Regexp.escape(%q|\'|)) => abcd\'efg

Resources