Escaping single and double quotes in a string in ruby? - ruby

How can I escape single and double quotes in a string?
I want to escape single and double quotes together. I know how to pass them separately but don't know how to pass both of them.
e.g: str = "ruby 'on rails" " = ruby 'on rails"

My preferred way is to not worry about escaping and instead use %q, which behaves like a single-quote string (no interpolation or character escaping), or %Q for double quoted string behavior:
str = %q[ruby 'on rails" ] # like single-quoting
str2 = %Q[quoting with #{str}] # like double-quoting: will insert variable
See https://docs.ruby-lang.org/en/trunk/syntax/literals_rdoc.html#label-Strings and search for % strings.

Use backslash to escape characters
str = "ruby \'on rails\" "

Here is a complete list:
From http://learnrubythehardway.org/book/ex10.html

You can use Q strings which allow you to use any delimiter you like:
str = %Q|ruby 'on rails" " = ruby 'on rails|

>> str = "ruby 'on rails\" \" = ruby 'on rails"
=> "ruby 'on rails" " = ruby 'on rails"

I would go with a heredoc if I'm starting to have to worry about escaping. It will take care of it for you:
string = <<MARKER
I don't have to "worry" about escaping!!'"!!
MARKER
MARKER delineates the start/end of the string. start string on the next line after opening the heredoc, then end the string by using the delineator again on it's own line.
This does all the escaping needed and converts to a double quoted string:
string
=> "I don't have to \"worry\" about escaping!!'\"!!\n"

I would use just:
str = %(ruby 'on rails ")
Because just % stands for double quotes(or %Q) and allows interpolation of variables on the string.

Here is an example of how to use %Q[] in a more complex scenario:
%Q[
<meta property="og:title" content="#{#title}" />
<meta property="og:description" content="#{#fullname}'s profile. #{#fullname}'s location, ranking, outcomes, and more." />
].html_safe

One caveat:
Using %Q[] and %q[] for string comparisons is not intuitively safe.
For example, if you load something meant to signify something empty, like "" or '', you need to use the actual escape sequences. For example, let's say qvar equals "" instead of any empty string.
This will evaluate to false
if qvar == "%Q[]"
As will this,
if qvar == %Q[]
While this will evaluate to true
if qvar == "\"\""
I ran into this issue when sending command-line vars from a different stack to my ruby script. Only Gabriel Augusto's answer worked for me.

Related

Regexp.escape adds weird escapes to a plain space

I stumbled over this problem using the following simplified example:
line = searchstring.dup
line.gsub!(Regexp.escape(searchstring)) { '' }
My understanding was, that for every String stored in searchstring, the gsub! would cause that line is afterwards empty. Indeed, this is the case for many strings, but not for this case:
searchstring = "D "
line = searchstring.dup
line.gsub!(Regexp.escape(searchstring)) { '' }
p line
It turns out, that line is printed as "D " afterwards, i.e. no replacement had been performed.
This happens to any searchstring containing a space. Indeed, if I do a
p(Regexp.escape(searchstring))
for my example, I see "D\\ " being printed, while I would expect to get "D " instead. Is this a bug in the Ruby core library, or did I misuse the escape function?
Some background: In my concrete application, where this simplified example is derived from, I just want to do a literal string replacement inside a long string, in the following way:
REPLACEMENTS.each do
|from, to|
line.chomp!
line.gsub!(Regexp.escape(from)) { to }
end
. I'm using Regexp.escape just as a safety measure in the case that the string being replaced contains some regex metacharacter.
I'm using the Cygwin port of MRI Ruby 2.6.4.
line.gsub!(Regexp.escape(searchstring)) { '' }
My understanding was, that for every String stored in searchstring, the gsub! would cause that line is afterwards empty.
Your understanding is incorrect. The guarantee in the docs is
For any string, Regexp.new(Regexp.escape(str))=~str will be true.
This does hold for your example
Regexp.new(Regexp.escape("D "))=~"D " # => 0
therefore this is what your code should look like
line.gsub!(Regexp.new(Regexp.escape(searchstring))) { '' }
As for why this is the case, there used to be a bug where Regex.escape would incorrectly handle space characters:
# in Ruby 1.8.4
Regex.escape("D ") # => "D\\s"
My guess is they tried to keep the fix as simple as possible by replacing 's' with ' '. Technically this does add an unnecessary escape character but, again, that does not break the intended use of the method.
This happens to any searchstring containing a space. Indeed, if I do a
p(Regexp.escape(searchstring))
for my example, I see "D\\ " being printed, while I would expect to get "D " instead. Is this a bug in the Ruby core library, or did I misuse the escape function?
This looks to be a bug. In my opinion, whitespace is not a Regexp meta character, there is no need to escape it.
Some background: In my concrete application, where this simplified example is derived from, I just want to do a literal string replacement inside a long string […]
If you want to do literal string replacement, then don't use a Regexp. Just use a literal string:
line.gsub!(from, to)

ruby on rails replace single-quotes with double-quote in a string

I am trying to replace a single-quote with double quotes inside a string, as following:
current_res = 25
lowest_res = 15
str = "The result of the child is '#{current_res}' and the lowest grade is '#{lowest_res }'."
I need the output to look like:
str = The result of the child is "25" and the lowest grade is "15".
I tried different method using gsub but nothing work so far. Any ideas?
If that's the only case you're covering where you need to show some output in double quoted string then. How about something simple like following
str = "The result of the child is \"#{current_res}\" and the lowest grade is \"#{lowest_res }\" ."
You can escape quotes in double quoted strings.

Phoenix string interpolation containing \n and name="abc" in HTML

I want to generate HTML content in phoenix. I'm not able to use interpolation while adding name="abc". I get an error at ".
Using \ in text also shows the \, e.g. text = "This is an name=\"abc\" string" gives text = "This is an name=\"abc\" string".
Can anyone please suggest how I can have a raw string containing name="abc"?
The string does contain only name="abc", the problem is that when you see it in the terminal, Elixir escapes the double quotes, so you can copy and paste it to your code. If in doubt, use IO.puts(text), and it will print the text without doing any changes to it:
iex(1)> text = "This is an name=\"abc\" string"
"This is an name=\"abc\" string"
iex(2)> IO.puts text
This is an name="abc" string
:ok
If you want to interpolate some double quotes into a string, you might try this:
iex(1)> text = "This is a name=#{"abc"} string"
"This is a name=abc string"
That didn't work. You need to do something extra:
iex(16)> text = "This is a name=#{"\"abc\""} string"
"This is a name=\"abc\" string"
When you write something like this:
text = "This is a name="abc" string"
You should wonder how is it that elixir knows that the last quote is the quote that terminates the string. In other words, why doesn't elixir think that this is your string:
text = "This is a name="
and the rest of the line is just garbage that doesn't follow elixir's syntax? In order to tell elixir that the double quote after the = sign is not the end of the string--but that it's just another character within the string--you escape the double quote, like this:
text = "This is a name=\"abc\" string"
Now, elixir will see the double quote after string as the termination of the string.
Next, it is a complete hassle to escape double quotes within a string, so elixir provides a means of avoiding that with the ~s sigil:
iex(17)> text = ~s{This is a name="abc" string}
"This is a name=\"abc\" string"
With the ~s sigil, you can use various character pairs to surround your string, e.g. () or <> or | | or / /. You need to use a character pair that is not found within the string--otherwise you will run into the same problem as with interior double quotes.
Finally, you can prove that the string name=\"abc\" has only 10 characters, i.e. the characters name="abc", like this:
iex(13)> s1 = ~s{name="abc"}
"name=\"abc\""
iex(14)> String.length s1
10

regex replace [ with \[

I want to write a regex in Ruby that will add a backslash prior to any open square brackets.
str = "my.name[0].hello.line[2]"
out = str.gsub(/\[/,"\\[")
# desired out = "my.name\[0].hello.line\[2]"
I've tried multiple combinations of backslashes in the substitution string and can't get it to leave a single backslash.
You don't need a regular expression here.
str = "my.name[0].hello.line[2]"
puts str.gsub('[', '\[')
# my.name\[0].hello.line\[2]
I tried your code and it worked correct:
str = "my.name[0].hello.line[2]"
out = str.gsub(/\[/,"\\[")
puts out #my.name\[0].hello.line\[2]
If you replace putswith p you get the inspect-version of the string:
p out #"my.name\\[0].hello.line\\[2]"
Please see the " and the masked \. Maybe you saw this result.
As Daniel already answered: You can also define the string with ' and don't need to mask the values.

Ruby string sub without regex back references

I'm trying to do a simple string sub in Ruby.
The second argument to sub() is a long piece of minified JavaScript which has regular expressions contained in it. Back references in the regex in this string seem to be effecting the result of sub, because the replaced string (i.e., the first argument) is appearing in the output string.
Example:
input = "string <!--tooreplace--> is here"
output = input.sub("<!--tooreplace-->", "\&")
I want the output to be:
"string \& is here"
Not:
"string & is here"
or if escaping the regex
"string <!--tooreplace--> is here"
Basically, I want some way of doing a string sub that has no regex consequences at all - just a simple string replace.
To avoid having to figure out how to escape the replacement string, use Regex.escape. It's handy when replacements are complicated, or dealing with it is an unnecessary pain. A little helper on String is nice too.
input.sub("<!--toreplace-->", Regexp.escape('\&'))
You can also use block notation to make it simpler (as opposed to Regexp.escape):
=> puts input.sub("<!--tooreplace-->") {'\&'}
string \& is here
Use single quotes and escape the backslash:
output = input.sub("<!--tooreplace-->", '\\\&') #=> "string \\& is here"
Well, since '\\&' (that is, \ followed by &) is being interpreted as a special regex statement, it stands to reason that you need to escape the backslash. In fact, this works:
>> puts 'abc'.sub 'b', '\\\\&'
a\&c
Note that \\\\& represents the literal string \\&.

Resources