How to replace "\n" but not "\n\n" etc. with " \n"?
text1 = "Hello\nWorld"
text1.sub! "\n", " \n"
=> "Hello \nWorld"
text2 = "Hello\n\nWorld"
text2.sub! "\n\n", " \n"
=> "Hello \n\nWorld"
SHOULD BE: => "Hello\n\nWorld"
You can use the regular expression /(?<!\n)\n(?!\n)/, which matches a \n only when it's not prefixed with another \n and not followed by a \n.
text1 = "Hello\nWorld"
# => "Hello\nWorld"
text1.sub /(?<!\n)\n(?!\n)/, " \n"
# => "Hello \nWorld"
text2 = "Hello\n\nWorld"
# => "Hello\n\nWorld"
text2.sub /(?<!\n)\n(?!\n)/, " \n"
# => "Hello\n\nWorld"
Here's another way:
r = /\n+/
"Hello\nWorld".sub(r) { |s| (s.size==1) ? " \n" : s }
#=> "Hello \nWorld"
"Hello\n\nWorld".sub(r) { |s| (s.size==1) ? " \n" : s }
#=> "Hello\n\nWorld"
and one more:
h = Hash.new { |h,k| h[k] = k }.update("\n"=>" \n")
#=> {"\n"=>" \n"}
"Hello\nWorld".sub(r,h)
#=> "Hello \nWorld"
"Hello\n\nWorld".sub(r,h)
#=> "Hello\n\nWorld"
In the latter method, each string of one or more consecutive newline characters is passed to the hash. If it's a single newline, "\n" is replaced with h["\n"] #=> " \n". If it's two or more newlines, say s = "\n\n", and h does not have a key equal to s (initally it won't), the key-value pair s=>s will be added to h (because of the default value defined for the hash) and s will be replaced by itself.
Another solution you could use:
string = "Hello\nWorld"
string.split("\n") == string.split("\n").reject(&:empty?) ? string.sub!("\n", " \n") : string
#=> "Hello \nWorld"
string = "Hello\n\nWorld"
string.split("\n") == string.split("\n").reject(&:empty?) ? string.sub!("\n", " \n") : string
#=> "Hello\n\nWorld"
I have the following program:
args = ["a", "b"]
cmd_args = args.map{|x| x.inspect}
str = cmd_args.join(' ')
puts str
The output is:
"a" "b"
I expect the output to be like the following (sub-string quoted with ' instead of "):
'a' 'b'
I don't want to do a gsub after string inspect because, in my real system, substring might contain ". For example:
args = ['a"c', "b"]
cmd_args = args.map{|x| x.inspect.gsub('"', '\'')}
str = cmd_args.join(' ')
puts str
will output:
'a\'c' 'b'
The " between a and c is wrongly replaced. My expected output is:
'a"c' 'b'
How can I make string inspect to quote strings with ' instead of "?
s = 'a"c'.inspect
s[0] = s[-1] = "'"
puts s.gsub("\\\"", "\"") #=> 'a"c'
You can't force String#inspect to use a single quote without rewriting or overwriting it.
Instead of x.inspect, you could substitute "'#{x}'", but then you would have to make sure you escape any ' characters that appear in x.
Here it is, working:
args = ["a", "b"]
cmd_args = args.map{|x| "'#{x}'" }
str = cmd_args.join(' ')
puts str
The output is:
'a' 'b'
I'm trying to populate a multi-dimensional array in ruby by reading from a file. Here is the code:
class Maze
attr_accessor :array
def initialize(filename)
handler = File.open(filename,"r")
#array = Array.new(10,Array.new(10))
n = 0;
i = 0;
while(line = handler.gets) do
i = 0
line.chomp.each_char do |char|
p char
#array[n][i] = char
i += 1
end #iterator over character in every line
n += 1
end #iterator over file lines
handler.close
end #constructor
end #class
a = Maze.new("maze.txt")
p a.array
Here is the content of the file:
##########
# #
# #### #
# # # #
# # # ?
# # # #
# # #
# #### #
# #
##########
However this line of code (the last line of code)
p a.array
Will print an array 10 by 10 but full of "#" symbols. No spaces nor "?". Something important to note is that
p char
In the block where I assign the array with values prints the right characters. It prints spaces at the right time and question marks etc... I know it's something very simple but it's bugging me and I think I need a fresh pair of eyes to look over it
Why is it that the array has only "#" symbols. Why aren't all the other characters such as " ", "#", "?" in my array? Is the assigning in my code wrongly coded
I'd write the code differently. It's not quite clear what you're trying to do, so here's two different things I'd do:
class Maze
attr_accessor :array
def initialize(filename)
#array = []
File.foreach(filename) do |line|
#array << line.chomp
end
end
end
a = Maze.new("maze.txt")
p a.array
puts a.array
Which outputs:
["##########", "# #", "# #### #", "# # # #", "# # # ?", "# # # #", "# # #", "# #### #", "# #", "##########"]
##########
# #
# #### #
# # # #
# # # ?
# # # #
# # #
# #### #
# #
##########
Or:
class Maze
attr_accessor :array
def initialize(filename)
#array = []
File.foreach(filename) do |line|
#array << line.chomp.split('')
end
end
end
a = Maze.new("maze.txt")
p a.array
puts a.array.map(&:join)
which outputs:
[["#", "#", "#", "#", "#", "#", "#", "#", "#", "#"], ["#", " ", " ", " ", " ", " ", " ", " ", " ", "#"], ["#", " ", "#", "#", "#", "#", " ", " ", " ", "#"], ["#", " ", "#", " ", " ", "#", " ", " ", " ", "#"], ["#", " ", "#", " ", " ", "#", " ", " ", " ", "?"], ["#", " ", "#", " ", " ", "#", " ", " ", " ", "#"], ["#", " ", "#", " ", " ", " ", " ", " ", " ", "#"], ["#", " ", "#", "#", "#", "#", " ", " ", " ", "#"], ["#", " ", " ", " ", " ", " ", " ", " ", " ", "#"], ["#", "#", "#", "#", "#", "#", "#", "#", "#", "#"]]
##########
# #
# #### #
# # # #
# # # ?
# # # #
# # #
# #### #
# #
##########
The primary problem in your code is you're using array references when you assign to the sub-arrays, which results in them all pointing to the same memory. I think you did that because you're used to another language where you have to predefine your array size. Ruby is more friendly than that, allowing us to append to an array easily. I used to << operator, but other methods exist to do the same thing; << is easier to see and understand.
Instead of opening the file, then using a while loop to iterate over it, it's more idiomatic to use foreach, which accomplishes the same thing and automatically closes the file when the block exits.
Also, instead of iterating over each line's characters, simply split the line using split('') which will return an array of characters. Append that to #array and move on.
The culprit is the way you are initializing the array in this line:
#array = Array.new(10,Array.new(10))
this is creating an array of 10 elements and it is initializing all of them with a pointer to another array of 10 elements. All the 10 elements will be sharing the same array. You can see a simplified example in here:
b = Array.new(3,Array.new(3))
b[0][0] = '00'
puts b # you'll see '00' printed 3 times!
One way to fix your program will be to create the array of rows first, then then initialize each row to a different array:
#array = Array.new(10)
for i in 0..9
# initialize each row to a unique array
#array[i] = Array.new(10)
end
# the rest of your code
For microarray data processing, I need to make a list of gene names from 1 to 654, like Gene_1 ... Gene_654.
My simple Ruby code produces the following:
1.upto(654).each { |i| print "Gene" }
The result is:
GeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGene
GeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGene
GeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGene
GeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGene
GeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGene
GeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGene
GeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGene
GeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGene
GeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGene
..................................
GeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGeneGene=> 1
irb(main):008:0>
How do I add a "postfix _#" in sequential incremental order to a printed string and put them in a column, like:
Gene_1
Gene_2
::::::
Gene_654
1.upto(654).each { |i| printf "%8s\t", "Gene_#{i}" }
Source: http://www.ruby-doc.org/core-2.0.0/Kernel.html#format-method
Edited to conform to the new requirements:
1.upto(654).each { |i| puts "Gene_#{i}" }
--output:--
Gene_1
Gene_2
...
Geen_654
I'd use:
str = 'Gene_0'
654.times { puts str.next! }
Which outputs:
Gene_1
...
Gene_654
If you need the text output to the same width, perhaps because you're going to append information to each line, use some formatting:
str = 'Gene_0'
654.times { puts '%8s ' % str.next! }
# >> Gene_1
...
# >> Gene_9
# >> Gene_10
...
# >> Gene_99
# >> Gene_100
...
# >> Gene_654
If you need columns across a page:
str = 'Gene_0'
654.times { print '%8s ' % str.next! }
puts
Which spaces them out in 8-space-wide columns.
By default %8s uses right alignment, which isn't always what you want. Instead you can use %-8s for left-alignment.
You can build an array containing the column headings:
str = 'Gene_0'
columns = []
654.times { columns << '%-8s' % str.next! }
puts columns.join(' ')
You could even use something like inject:
str = 'Gene_0'
columns = []
(1..654).inject(columns) { |a, i| a.push('%-8s' % str.next!) }
puts columns.join(' ')
But that starts to add code that doesn't really help.
The OP asked:
...how to add " " to the result...
The output above doesn't make it easy to see the whitespace automatically appended to the output by '%8s ', so I tweaked the format-string to make it more obvious by wrapping the output in double-quotes:
str = 'Gene_0'
654.times { puts '"%8s "' % str.next! }
And here's the corresponding output, trimmed down to show how the format string maintains the column width as the string value increments:
# >> " Gene_1 "
...
# >> " Gene_9 "
# >> " Gene_10 "
...
# >> " Gene_99 "
# >> "Gene_100 "
...
# >> "Gene_654 "
If you want all the white-space to occur at the end of the column, use a left-alignment:
str = 'Gene_0'
654.times { puts '"%-8s "' % str.next! }
Which outputs:
# >> "Gene_1 "
...
# >> "Gene_9 "
# >> "Gene_10 "
...
# >> "Gene_99 "
# >> "Gene_100 "
...
# >> "Gene_654 "
I'm having difficulty reading a file with escaped characters in Ruby...
My text file has the string "First Line\r\nSecond Line" and when I use File.read, I get a string back that escapes my escaped characters: "First Line\r\nSecond Line"
These two strings are not the same things...
1.9.2-p318 :006 > f = File.read("file.txt")
=> "First Line\\r\\nSecond Line"
1.9.2-p318 :007 > f.count('\\')
=> 2
1.9.2-p318 :008 > f = "First Line\r\nSecond Line"
=> "First Line\r\nSecond Line"
1.9.2-p318 :009 > f.count('\\')
=> 0
How can I get the File.read to not escape my escaped characters?
Create a method to remove all the additional escape characters that the File.Read method added, like this:
# Define a method to handle unescaping the escape characters
def unescape_escapes(s)
s = s.gsub("\\\\", "\\") #Backslash
s = s.gsub('\\"', '"') #Double quotes
s = s.gsub("\\'", "\'") #Single quotes
s = s.gsub("\\a", "\a") #Bell/alert
s = s.gsub("\\b", "\b") #Backspace
s = s.gsub("\\r", "\r") #Carriage Return
s = s.gsub("\\n", "\n") #New Line
s = s.gsub("\\s", "\s") #Space
s = s.gsub("\\t", "\t") #Tab
s
end
Then see it in action:
# Create your sample file
f = File.new("file.txt", "w")
f.write("First Line\\r\\nSecond Line")
f.close
# Use the method to solve your problem
f = File.read("file.txt")
puts "BEFORE:", f
puts f.count('\\')
f = unescape_escapes(f)
puts "AFTER:", f
puts f.count('\\')
# Here's a more elaborate use of it
f = File.new("file2.txt", "w")
f.write("He used \\\"Double Quotes\\\".")
f.write("\\nThen a Backslash: \\\\")
f.write('\\nFollowed by \\\'Single Quotes\\\'.')
f.write("\\nHere's a bell/alert: \\a")
f.write("\\nThis is a backspaces\\b.")
f.write("\\nNow we see a\\rcarriage return.")
f.write("\\nWe've seen many\\nnew lines already.")
f.write("\\nHow\\sabout\\ssome\\sspaces?")
f.write("\\nWe'll also see some more:\\n\\ttab\\n\\tcharacters")
f.close
# Read the file without the method
puts "", "BEFORE:"
puts File.read("file2.txt")
# Read the file with the method
puts "", "AFTER:"
puts unescape_escapes(File.read("file2.txt"))
You could just hack them back in.
foo = f.gsub("\r\n", "\\r\\n")
#=> "First Line\\r\\nSecond Line"
foo.count("\\")
#=> 2