How do I use string.tr to replace double quotes with single ones in Ruby? - ruby

How do I use string.tr to replace double quotes with single ones in Ruby?

'abc "def" ghi'.tr('"', "'") # => abc 'def' ghi

Besides tr, you can also use gsub
irb(main):001:0> 'abc "def" ghi'.gsub(/"/,"'")
=> "abc 'def' ghi"

Related

Gsub causing part of string to be substituted

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?
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 \\.
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
++++
It's possible you just need a higher dose of escaping:
a.gsub(/'/, "\\\\'" )
Result:
abc \'def\' ghi

Ruby: eval with string interpolation

I don't understand, why eval works like this:
"123 #{456.to_s} 789" # => "123 456 789"
eval('123 #{456.to_s} 789') # => 123
How can I interpolate into a string inside eval?
Update:
Thank you, friends. It worked.
So if you have a string variable with #{} that you want to eval later, you should do it as explained below:
string = '123 #{456} 789'
eval("\"" + string + "\"")
# => 123 456 789
or
string = '123 #{456} 789'
eval('"' + string + '"')
# => 123 456 789
What's happening, is eval is evaluating the string as source code. When you use double quotes, the string is interpolated
eval '"123 #{456.to_s} 789"'
# => "123 456 789"
However when you use single quotes, there is no interpolation, hence the # starts a comment, and you get
123 #{456.to_s} 789
# => 123
The string interpolation happens before the eval call because it is the parameter to the method.
Also note the 456.to_s is unnecessary, you can just do #{456}.
You wanted:
eval('"123 #{456.to_s} 789"')
. . . hopefully you can see why?
The code passed to the interpretter from eval is exactly as if you had written it (into irb, or as part of a .rb file), so if you want an eval to output a string value, the string you evaluate must include the quotes that make the expression inside it a String.

Single quotes vs double quotes

I am trying to split a string by three consecutive newlines ("\n\n\n"). I was trying str.split('\n\n\n') and it didn't work, but when I changed to str.split("\n\n\n"), it started to work. Could anyone explain to me why such behaviour happens?
String in single quotes is a raw string. So '\n\n\n' is three backslashes and three n, not three line feeds as you expected. Only double quotes string can be escaped correctly.
puts 'abc\nabc' # => abc\nabc
puts "abc\nabc" # => abc
# abc
Single quoted string have the actual/literal contents, e.g.
1.9.3-p194 :003 > puts 'Hi\nThere'
Hi\nThere
=> nil
Whereas double-quoted string 'interpolate' the special characters (\n) and do the line feed, e.g.
1.9.3-p194 :004 > puts "Hi\nThere"
Hi
There
=> nil
1.9.3-p194 :005 >
Best practice Recommendations:
Choose single quotes over double quotes when possible (use double quotes as needed for interpolation).
When nesting 'Quotes inside "quotes" somewhere' put the double ones inside the single quotes
In single-quoted string literals, backslashes need not be doubled
'\n' == '\\n'

Ruby gsub doesn't escape single-quotes

I don't understand what is going on here. How should I feed gsub to get the string "Yaho\'o"?
>> "Yaho'o".gsub("Y", "\\Y")
=> "\\Yaho'o"
>> "Yaho'o".gsub("'", "\\'")
=> "Yahooo"
\' means $' which is everything after the match.
Escape the \ again and it works
"Yaho'o".gsub("'", "\\\\'")
"Yaho'o".gsub("'", "\\\\'")
Because you're escaping the escape character as well as escaping the single quote.
This will also do it, and it's a bit more readable:
def escape_single_quotes(str)
str.gsub(/'/) { |x| "\\#{x}" }
end
If you want to escape both a single-quote and a backslash, so that you can embed that string in a double-quoted ruby string, then the following will do that for you:
def escape_single_quotes_and_backslash(str)
str.gsub(/\\|'/) { |x| "\\#{x}" }
end

How to add a single backslash character to a string in Ruby?

I want to insert backslash before apostrophe in "children's world" string. Is there a easy way to do it?
irb(main):035:0> s = "children's world"
=> "children's world"
irb(main):036:0> s.gsub('\'', '\\\'')
=> "childrens worlds world"
Answer
You need some extra backslashes:
>> puts "children's world".gsub("'", '\\\\\'')
children\'s world
or slightly more concisely (since you don't need to escape the ' in a double-quoted string):
>> puts "children's world".gsub("'", "\\\\'")
children\'s world
or even more concisely:
>> puts "children's world".gsub("'") { "\\'" }
children\'s world
Explanation
Your '\\\'' generates \' as a string:
>> puts '\\\''
\'
and \' is a special replacement pattern in Ruby. From ruby-doc.org:
you may refer to some special match variables using these combinations ... \' corresponds to $', which contains string after match
So the \' that gsub sees in the second argument is being interpreted as a special pattern (everything in the original string after the match) instead of as a literal \'.
So what you want gsub to see is actually \\', which can be produced by '\\\\\'' or "\\\\'".
Or, if you use the block form of gsub (gsub("xxx") { "yyy" }) then Ruby takes the replacement string "yyy" literally without trying to apply replacement patterns.
Note: If you have to create a replacement string with a lot of \s you could take advantage of the fact that when you use /.../ (or %r{...}) you don't have to double-escape the backslashes:
>> puts "children's world".gsub("'", /\\'/.source)
children\'s world
Or you could use a single-quoted heredoc: (using <<'STR' instead of just <<STR)
>> puts "children's world".gsub("'", <<'STR'.strip)
\\'
STR
children\'s world
>> puts s.gsub("'", "\\\\'")
children\'s world
Your problem is that the string "\'" is meaningful to gsub in a replacement string. In order to make it work the way you want, you have to use the block form.
s.gsub("'") {"\\'"}

Resources