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

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.

Related

How to get gsub! to recognize different characters (uppercase, lowercase)

print "Enter your text here:"
user_text = gets.chomp
user_text_2 = user_text.gsub! "Damn", "Darn"
user_text_3 = user_text.gsub! "Shit", "Crap"
puts "Here is your edited text: #{user_text}"
I would like that code to also recognize when I use the lowercase versions of Shit and Damn and replace them with the substitute words. Right now it only recognizes when I type the words in with an uppercase first word. Is there any way to get it to recognize the lowercase words too, without adding more gsub! lines of code?
You can specify the i flag on your patten to ignore case:
user_text_2 = user_text.gsub! /Damn/i, "Darn"
Just a very short solution:
user_text.gsub!(/[Dd]amn/, 'Darn')
The more general approach, if this is what you want, is with an i which makes the regex case-insensitive.
user_text.gsub!(/damn/i, 'Darn')
You can do that with a Regexp and the i option, that makes the Regexp case insensitive:
foo = 'foo Foo'
foo.gsub(/foo/, 'bar')
#=> "bar Foo"
foo.gsub(/foo/i, 'bar') # with i
#=> "bar bar"
Use regular expressions instead of strings. So /damn/i instead of "damn". The 'i' at the end of a regular expression means ignore casing.

Ruby single and double quotes

I've recently been coding in Ruby and have come from Python, where single and double quotes made no difference to how the code worked as far as I know.
I moved to Ruby to see how it worked, and to investigate the similarities between Ruby and Python.
I was using single-quoted strings once and noticed this:
hello = 'hello'
x = '#{hello} world!'
puts x
It returned '#{hello} world!' rather than 'hello world!'.
After noticing this I tried double quotes and the problem was fixed. Now I'm not sure why that is.
Do single and double quotes change this or is it because of my editor (Sublime text 3)? I'm also using Ruby version 2.0 if it works differently in previous versions.
In Ruby, double quotes are interpolated, meaning the code in #{} is evaluated as Ruby. Single quotes are treated as literals (meaning the code isn't evaluated).
var = "hello"
"#{var} world" #=> "hello world"
'#{var} world' #=> "#{var} world"
For some extra-special magic, Ruby also offers another way to create strings:
%Q() # behaves like double quotes
%q() # behaves like single quotes
For example:
%Q(#{var} world) #=> "hello world"
%q(#{var} world) #=> "#{var} world"
You should read the Literals section of the official Ruby documentation.
It is very concise, so you need to read carefully. But it explains the difference between double-quoted and single-quoted strings, and how they are equivalent to %Q/.../ and %q/.../ respectively.
If you enclose Ruby string in single qoutes, you can't use interpolation. That's how Ruby works.
Single-quoted strings don't process escape sequence \ and they don't do string interpolation.
For a better understanding, take a look at String concatenation vs. interpolation
To answer your question, you have to use "" when you want to do string interpolation:
name = 'world'
puts "Hello #{name}" # => "Hello world"
Using escape sequence:
puts 'Hello\nworld' # => "Hello\nworld"
puts "Hello\nworld" # => "Hello
world"
Ruby supports single-quoted string, for many uses like as follow:
>> 'foo'
=> "foo"
>> 'foo' + 'bar'
=> "foobar"
In above example, those two types of strings are identical. We can use double quote in place of single quote and we will get same output like above example.
As you face problem, while using interpolation in single quoted string because Ruby do not interpolate into single-quoted string. I am taking one example for more understanding:
>> '#{foo} bar'
=> "\#{foo} bar"
Here you can see that return values using double-quoted strings, which requires backslash to escape special characters such as #.
Single quoted string often useful because they are truly literal.
In the string interpolation concept, the essential difference between using single or double quotes is that double quotes allow for escape sequences while single quotes do not.
Let's take an example:
name = "Mike"
puts "Hello #{name} \n How are you?"
The above ruby code with string interpolation will interpolate the variable called name which is written inside brackets with its original value which is Mike. And it will also print the string How are you? in a separate line since we already placed an escape sequence there.
Output:
Hello Mike
How are you?
If you do the same with single quotes, it will treat the entire string as a text and it will print as it is including the escape sequence as well.
name = Mike'
puts 'Hello #{name} \n How are you'?
Output:
Hello #{name} \n How are you?

How do I remove backslashes from a JSON string?

I have a JSON string that looks as below
'{\"test\":{\"test1\":{\"test1\":[{\"test2\":\"1\",\"test3\": \"foo\",\"test4\":\"bar\",\"test5\":\"test7\"}]}}}'
I need to change it to the one below using Ruby or Rails:
'{"test":{"test1":{"test1":[{"test2":"1","test3": "foo","test4":"bar","test5":"bar2"}]}}}'
I need to know how to remove those slashes.
To avoid generating JSON with backslashes in console, use puts:
> hash = {test: 'test'}
=> {:test=>"test"}
> hash.to_json
=> "{\"test\":\"test\"}"
> puts hash.to_json
{"test":"test"}
You could also use JSON.pretty_generate, with puts of course.
> puts JSON.pretty_generate(hash)
{
"test": "test"
}
Use Ruby's String#delete! method. For example:
str = '{\"test\":{\"test1\":{\"test1\":[{\"test2\":\"1\",\"test3\": \"foo\",\"test4\":\"bar\",\"test5\":\"test7\"}]}}}'
str.delete! '\\'
puts str
#=> {"test":{"test1":{"test1":[{"test2":"1","test3": "foo","test4":"bar","test5":"test7"}]}}}
Replace all backslashes with empty string using gsub:
json.gsub('\\', '')
Note that the default output in a REPL uses inspect, which will double-quote the string and still include backslashes to escape the double-quotes. Use puts to see the string’s exact contents:
{"test":{"test1":{"test1":[{"test2":"1","test3": "foo","test4":"bar","test5":"test7"}]}}}
Further, note that this will remove all backslashes, and makes no regard for their context. You may wish to only remove backslashes preceding a double-quote, in which case you can do:
json.gsub('\"', '')
I needed to print a pretty JSON array to a file. I created an array of JSON objects then needed to print to a file for the DBA to manipulate.
This is how i did it.
puts(((dirtyData.gsub(/\\"/, "\"")).gsub(/\["/, "\[")).gsub(/"\]/, "\]"))
It's a triple nested gsub that removes the \" first then removes the [" lastly removes the "]
I hope this helps
I tried the earlier approaches and they did not seem to fix my issue. My json still had backslashes. However, I found a fix to solve this issue.
myuglycode.gsub!(/\"/, '\'')
Use JSON.parse()
JSON.parse("{\"test\":{\"test1\":{\"test1\":[{\"test2\":\"1\",\"test3\": \"foo\",\"test4\":\"bar\",\"test5\":\"test7\"}]}}}")
> {"test"=>{"test1"=>{"test1"=>[{"test2"=>"1", "test3"=>"foo", "test4"=>"bar", "test5"=>"test7"}]}}}
Note that the "json-string" must me double-quoted for this to work, otherwise \" would be read as is instead of being "translated" to " which return a JSON::ParserError Exception.

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.

Replacing regex capture with the same capture and an extra string

I am trying to escape certain characters in a string. In particular, I want to turn
abc/def.ghi into abc\/def\.ghi
I tried to use the following syntax:
1.9.3p125 :076 > "abc/def.ghi".gsub(/([\/.])/, '\\\1')
=> "abc\\1def\\1ghi"
Hmm. This behaves as if capture replacements didn't work. Yet, when I tried this:
1.9.3p125 :075 > "abc/def.ghi".gsub(/([\/.])/, '\1')
=> "abc/def.ghi"
... I got the replacement to work, but, of course, my prefixes weren't part of it.
What is the correct syntax to do something like this?
This should be easier
gsub(/(?=[.\/])/, "\\")
If you are trying to prepare a string to be used as a regex pattern, use the right tool:
Regexp.escape('abc/def.ghi')
=> "abc/def\\.ghi"
You can then use the resulting string to create a regex:
/#{ Regexp.escape('abc/def.ghi') }/
=> /abc\/def\.ghi/
or:
Regexp.new(Regexp.escape('abc/def.ghi'))
=> /abc\/def\.ghi/
From the docs:
Escapes any characters that would have special meaning in a regular expression. Returns a new escaped string, or self if no characters are escaped. For any string, Regexp.new(Regexp.escape(str))=~str will be true.
Regexp.escape('\*?{}.') #=> \\\*\?\{\}\.
You can pass a block to gsub:
>> "abc/def.ghi".gsub(/([\/.])/) {|m| "\\#{m}"}
=> "abc\\/def\\.ghi"
Not nearly as elegant as #sawa's answer, but it was the only way I could find to get it to work if you need the replacing string to contain the captured group/backreference (rather than inserting the replacement before the look-ahead).

Resources