how to prevent escaping when using newlines in text interpolation (Ruby) - ruby

The following three lines of code:
array = ["line 2", "line 3"]
foo = array.join("\n")
bar = "line 1\n#{foo}\nline4"
result in
"line 1\nline 2\nline 3\nline4"
is it possible to combine the 2nd and 3rd line using interpolation? The following doesn't work:
bar = "line 1\n#{array.join('\n')}\nline4"
because it adds an extra backslash:
"line 1\nline 2\\nline 3\nline4"

You need to use double-quotes around "\n" if you want Ruby to treat it as a newline character instead of two separate characters:
bar = "line 1\n#{array.join("\n")}\nline4"
^^^^

Related

How to convert [abc\tdef\tghi] to ["abc" "def" "ghi"] in Mac Terminal?

I have the following variable in Terminal
echo $VAR1
abc def ghi
<- Separated by tab
How can I convert this to
"abc" "def" "ghi"
with single space in-between?
In zsh, you can break your string up into an array of quoted words with
var1=$'abc\tdef\tghi'
words=( "${(qqq)=var1}" )
and then turn it back into a single string if wanted with
var2="${words[*]}"
printf "%s\n" "$var2" # prints "abc" "def" "ghi"
Or to skip the intermediate array if you don't need it:
var2=${(A)${(qqq)=var1}}
Assuming the variable contains actual tab characters (not backslashes followed by "t"), you can replace tabs with " " while expanding the variable (see here, a ways down in the list of modifiers), and also add quotes at the beginning and end, like this:
"\"${VAR1//$'\t'/\" \"}\""
There's a rather complex mix of quoting and escaping modes here. The double-quotes at the very beginning and end make the whole thing a double-quoted string, so the shell doesn't do anything weird to whitespace in it. The various escaped double-quotes in it will all be treated as literal characters (because they're escaped), and just be part of the output. And the pattern string, $'\t', is in ANSI-C quoting mode, so that the \t gets converted to an actual tab character.
Here's a couple of examples of using it:
% VAR1=$'abc\tdef\tghi' # Define a variable with actual tab characters
% echo "\"${VAR1//$'\t'/\" \"}\"" # Pass the converted version to a command
"abc" "def" "ghi"
% VAR2="\"${VAR1//$'\t'/\" \"}\"" # Store converted version in another variable
% echo "$VAR2"
"abc" "def" "ghi"
This could do what you want
echo -e "abc\tdef\tghi\tjhg\tmnb" | sed -ne 's/\t/" "/g; s/.*/"\0"/p'
Result:
"abc" "def" "ghi" "jhg" "mnb"
You may leverage awk. For example:
user$ $var='abc\tdef\tghi'
user$ $echo -e ${var}
(output)>>> abc def ghi
user$ $echo -e ${var} | awk -F '\t' '{ for (i=1; i <NF; i++) {printf "\"%s\" ", $i}; printf "\"%s\"\n", $NF}'
(output)>>> "abc" "def" "ghi"

Ruby - How to get rid of escape character and "\n" while converting string to hash value?

In Ruby, i'm trying to convert a string to a hash value. It shows up with escapse character and "\n" in the string.
Eg:
hashex = { keyex: 'example "test" line 1
line 2 "test2"'}
puts hashex
It is printing the result as
{:keyex=>"example \"test\" line 1\n line 2 \"test2\""}
I need to get the result as
{ keyex: 'example "test" line 1
line 2 "test2"'}
preserving the newline (not '\n') and the "". Kindly help.
Note
{:keyex=>"example \"test\" line 1\n line 2 \"test2\""}
is just the way Ruby represents the hash. It is 100% the same object as :
{ keyex: 'example "test" line 1
line 2 "test2"'}
even though it might look different.
Code
You could replace "\\n" from inspect with newlines, \" with " and " with ' :
hashex = { keyex: 'example "test" line 1
line 2 "test2"'}
puts hashex.inspect.gsub("\\n", "\n").gsub('"', "'").gsub("\\'",'"')
# {:keyex=>'example "test" line 1
# line 2 "test2"'}

Ruby one liner to replace only lines that match, discard others

Looking for the ruby one liner substitute to print out a substitution only if the line matches the regular expression:
echo -e "Line 1\nLine 2\nLine 3" | perl -ne "print if s/Line 2/Line 2 replaced, others discarded/g"
Input:
Line 1
Line 2
Line 3
Output:
Line 2 replaced, others discarded
As I know, there is no equivalent to -ne shorthand in ruby. So it will be little longer:
echo -e "Line 1\nLine 2\nLine 3" | ruby -e 'puts $<.read.lines.map {|l| l =~ /Line 2/ ? l.gsub(/Line 2/, "Line 2 replaced, others discarded") : nil }.compact'
Where:
$< also ARGF (docs) is Stream for file argument or STDIO
$<.read will read it all to string
$<.read.lines split by new line character, returns array
map {|l| ... } will collect result of expression in a block to new array
l =~ /Line 2/ check if string match Regex
l.gsub(/Line 2/, "Line 2 replaced") will replace all "Line 2" to "Line 2 replaced"
.compact will remove nil values from array (return new array without nil's)
puts [] will print each element of array on new line
Probably ruby is not a best chose for this task, I would choose sed or do it in text editor. Most of text editors can find and replace by regex nowdays

Replace the pipe character "|" with line breaks?

I am trying to use Regex in my Ruby program to convert "|" character into a line breaker, so for example:
# convert("title|subtitle") => "title \n subtitle"
The regex I'm trying is the following:
title_params =~ s/\|/\\n/
But I kept getting errors saying that "|" is not recognized.
Regex is not needed for this simple problem:
=> puts "foo|bar".tr("|","\n")
foo
bar
I don't really know the syntax of your way of doing this but this works fine for me.
>> a = "title | subtitle"
=> "title | subtitle"
>> a.gsub(/\|/,"\n")
=> "title \n subtitle"

Building multi-line strings, programmatically, in Ruby

Here's something I often do when programming:
code = ''
code << "next line of code #{something}" << "\n"
code << "another line #{some_included_expression}" << "\n"
Is there some better way than having << "\n" or + "\n" on every line? This seems quite inefficient.
I'm interested in Ruby solutions, in particular. I'm thinking something like
code = string.multiline do
"next line of code #{something}"
"another line #{some_included_expression}"
end
If you're looking to build a block of text, the easy way to do it is to just use the % operator. For example:
code = %{First line
second line
Third line #{2 + 2}}
'code' will then be
"First line\n second line\n Third line 4"
This would be one way:
code = []
code << "next line of code #{something}"
code << "another line #{some_included_expression}"
code.join("\n")
Use <<- operator:
code = <<-CODE
var1 = "foo"
var2 = "bar"
CODE
It would work for you to just embed ...\n" in your strings, I suppose. Here is a fun way to do it:
class String
def / s
self << s << "\n"
end
end
then
f = "" # => ""
f / 'line one' # => "line one\n"
f / 'line two' # => "line one\nline two\n"
f / 'line three' # => "line one\nline two\nline three\n"
This would enable something like:
"" / "line 1" / "line 2" / "line 3" # => "line 1\nline 2\nline 3\n"
Or even:
f/
"line one"/
"line two"/
"line three" # => "line one\nline two\nline three\n"
Here's a method presented here:
str = <<end.margin
|This here-document has a "left margin"
|at the vertical bar on each line.
|
| We can do inset quotations,
| hanging indentions, and so on.
end
This is accomplished by using this:
class String
def margin
arr = self.split("\n") # Split into lines
arr.map! {|x| x.sub!(/\s*\|/,"")} # Remove leading characters
str = arr.join("\n") # Rejoin into a single line
self.replace(str) # Replace contents of string
end
end
I guess the question with this is: does the lack of portability / presence of monkey patching make this solution bad.
What's wrong with:
code = "next line of code #{something}\n"+
"another line #{some_included_expression}"
You could place your multi-line text in a file, and use ERB to parse it (note ERB is included with Ruby)
require 'erb'
multi_line_string = File.open("multi_line_string.erb", 'r').read
template = ERB.new(multi_line_string)
template.result(binding)
(ERB can access variables from a Binding, an object that provides access to the instance methods and variables that are owned by another object. By setting it to "binding" it points to itself)
Documentation here.

Resources