I am currently trying to create a ruby algorithm to execute the following:
l = Array.new
Given array is text in the form of an array and has three manifests each titled Section No. 1, Section No. 2, Section No. 3 respectively.
Put the entire text in one string by looping through the array(l) and adding each line to the one big string each time.
Split the string using the split method and the key word "Section No." This will create an array with each element being one section of the text.
Loop through this new array to create files for each element.
So far I have the following:
a = l.join ''
b = Array.new
b = a.split ("Section No.")`
How would I go writing the easiest method to the third part?
Should only be about 2-3 lines.
Output would be the creation of three files each named after the manifest titles.
"Complex Version"
file_name = "Section"
section_number = "1"
new_text = File.open(file_name + section_number, 'w')
i = 0
n= 1
while i < l.length
if (l[i]!= "SECTION") and (l[i+1]!= "No")
new_text.puts l[i]
i = i + 1
else
new_text.close
section_number = (section_number.to_i +1).to_s
new_text = File.open(file_name + section_number, "w")
new_text.puts(l[i])
new_text.puts(l[i+1])
i=i+2
end
end
b.each_with_index(1) do |text, index|
File.write "section_#{index}.txt", text
end
To answer your most basic question, you could probably get away with:
sections.each_with_index do |section, index|
File.open("section_#{index}.txt", 'w') { |file| file.print section }
end
Here's an alternate solution:
input_string = "This should be your manifest string"
starting_string = "Section No."
copy_input_string = input_string.clone
sections = []
while(copy_input_string.length > 0)
index_of_next_start = copy_input_string.index(starting_string, starting_string.length) || copy_input_string.length
sections.push(copy_input_string.slice!(0...index_of_next_start))
end
sections.each_with_index do |section, index|
File.open("section_#{index}.txt", 'w') { |file| file.print section }
end
create string s by putting a space between each string in l
s = l.join ' '
split on 'Section No.' - note that 'Section No.' no longer appears in a
a = s.split('Section No.')
throw away the part before the first section
a = a[1..-1]
create the files
a.each do |section|
File.open('Section' + section.strip[0], 'w') do |file_handle|
file_handle.puts section
end
end
Related
So I am creating a class in ruby where in I will be able to insert my data on a text file and then read, find from it but I am stuck on delete as well update/edit.
Basically I created a method called "find" and I made it as a reference on my "delete" method.
def find(keyword="")
if keyword
person = People.read_people
found = person.select do |pip|
pip.name.downcase.include?(keyword.downcase) ||
pip.age.downcase.include?(keyword.downcase) ||
pip.country.downcase.include?(keyword.downcase)
end
found.each do |person|
puts person.name + " | " + person.age + " | " + person.country
end
else
puts "find using a key phrase eg. 'find sam' \n\n"
end
end
def list
puts "\nListing People \n\n".upcase
people = People.read_people
people.each do |person|
puts person.name + " | " + person.age + " | " + person.country
end
end
def delete(keyword="")
if keyword
person = People.read_people
found = person.select do |pip|
pip.name.downcase.include?(keyword.downcase) ||
pip.age.downcase.include?(keyword.downcase) ||
pip.country.downcase.include?(keyword.downcase)
end
person.delete(found)
else
puts "find using a key phrase eg. 'find josh' \n\n"
end
end
As you can see I was trying to delete the supplied keyword from the array (w/c was save on a text file) via class method called read_people. Here's how it looks like:
def self.read_people
# read the people file
# return instances of people
people = []
if file_usable?
file = File.new(##filepath, 'r')
file.each_line do |line|
people << People.new.import_line(line.chomp)
end
file.close
end
return people
end
def import_line(line)
line_array = line.split("\t")
#name, #age, #country = line_array
return self
end
How can I fix this and delete the found item via keyword?
See the actual codes here: https://repl.it/repls/VastWildFact
Change
person.delete(found)
to
person -= found # Equivalent to person = person - found
It should work as per https://ruby-doc.org/core-2.2.0/Array.html#method-i-2D
ary - other_ary → new_ary
Returns a new array that is a copy of the original array, removing any items that also appear in other_ary. The order is preserved from the original array.
It compares elements using their hash and eql? methods for efficiency.
Example: [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ]
Another solution is to use reject as follows:
person.reject! do |pip|
pip.name.downcase.include?(keyword.downcase) ||
pip.age.downcase.include?(keyword.downcase) ||
pip.country.downcase.include?(keyword.downcase)
end
Basically you're going to want an export_people and write_people method that'll look something like this:
def self.export_people(people)
people.map do |person|
[person.name, person.age, person.country].join("\t")
end
end
def self.write_people(people)
File.new(##filepath, 'w') do |f|
f.write(export_people(people))
end
end
# Usage:
Person.write_people(array_of_people)
With the above code, you'd call the modified delete method as detailed in Tarek's answer, and then Person.write_people(array_of_people) to write back to the file.
I am writing a braille converter. I have this method to handle the top line of a braille character:
def top(input)
braille = ""
#output_first = ""
#top.each do |k, v|
input.chars.map do |val|
if k.include?(val)
braille = val
braille = braille.gsub(val, v)
#output_first = #output_first + braille
end
end
end
#output_first
end
I'm repeating the same each loop for the middle and bottom lines of a character. The only thing that is different from the method above is that the #top is replaced with #mid and #bottom to correspond to the respective lines.
Trying to figure a way to simplify the each loop so I can call it on top, mid and bottom lines.
You can put the loop in a separate method.
def top(input)
#output_first = handle_line(#top)
end
def handle_line(line)
result = ''
line.each do |k, v|
input.chars.map do |val|
if k.include?(val)
braille = val
braille = braille.gsub(val, v)
result = result + braille
end
end
end
result
end
You can then call handle_line in your #mid and #bottom processing
I'm not sure whats in the #top var but I believe braille has limited number of characters and therefore I would consider some map structure
BRAILLE_MAP = {
'a' => ['..',' .','. '], # just an example top,mid,bot line for character
'b' => ['..','..',' '],
# ... whole map
}
def lines(input)
top = '' # representation of each line
mid = ''
bot = ''
input.each_char do |c|
representation = BRAILLE_MAP[c]
next unless representation # handle invalid char
top << representation[0] # add representation to each line
mid << representation[1]
bot << representation[2]
end
[top,mid,bot] # return the lines
end
There may be better way to handle those 3 variables, but I cant think of one right now
I'm new to ruby i would like to know how can i split element containing special character.
I have the following array :
my_array = ["sh.please-word", ".things-to-do" , "#cool-stuff", "span.please-word-not"]
my_array.slice!(0..1)
puts my_array
=>#cool-stuff
=>span.please-word
i want it to split array elements that doesn't start with either a dot(.) or a (#) and return the list like this:
.please-word
.things-to-do
#cool_stuff
.please-word-not
i tried to use the slice method for a string which works perfectly, but when i try with the array element it doesn't work.
this is what i have done so far.
list_of_selectors = []
file = File.open("my.txt")
file.each_line do |line|
list_of_selectors << line.split(' {')[0] if line.start_with? '.' or line.start_with? '#'
end
while line = file.gets
puts line
end
i = 0
while i < list_of_selectors.length
puts "#{list_of_selectors[i]}"
i += 1
end
list = []
list_of_selectors.each { |x|
list.push(x.to_s.split(' '))
}
list_of_selectors = list
puts list_of_selectors
list_of_selectors.map! { |e| e[/[.#].*/]}
puts list_of_selectors
result_array = my_array.map { |x| x[/[.#].*/] }
# => [".please-word", ".things-to-do", "#cool-stuff", ".please-word-not"]
The above uses a regular expression to extract the text, beginning with either a dot(.) or a hashtag (#), and return it in the resulting array.
I am trying to search for a bunch of print statements that I want to filter as follows:
I want to select all dbg_printfs.
Out of all of those I want to select those that have value.stringValue().
Out of those I only want those that do not have value.stringValue().value().
Finally, I want to replace those lines with value.stringValue() to value.stringValue().value().
I don't know why my current code isn't working?
fileObj = File.new(filepath, "r")
while (line = fileObj.gets)
line.scan(/dbg_printf/) do
line.scan(/value.stringValue()/) do
if !line.scan(/\.value\(\)/)
line.gsub!(/value.stringValue()/, 'value.stringValue().value()')
end
end
end
fileObj.close
Primarily, your problem seems to be that you expect altering the string returned from gets to alter the contents of the file. There isn't actually that kind of relationship between strings and files. You need to explicitly write the modifications to the file. Personally, I would probably write that code like this:
modified_contents = IO.readlines(filepath).map do |line|
if line =~ /dbg_printf/
# This regex just checks for value.stringValue() when not followed by .value()
line.gsub /value\.stringValue\(\)(?!\.value\(\))/, 'value.stringValue().value()'
else
line
end
end
File.open(filepath, 'w') {|file| file.puts modified_contents }
The problem is that you are not writing the changed lines back to the same file or a new file. To write them to the same file, read the file into an array, change the array and then write it back to the same or a different file (the later being the more prudent). Here's one way to do that with few lines of code.
Code
fin_name and fout_name are the names (with paths) of the input and output files, respectively.
def filter_array(fin_name, fout_name)
arr_in = File.readlines(fin_name)
arr_out = arr_in.map { |l| (l.include?('dbg_printfs') &&
l.include?('value.stringValue()') &&
!l.include?('value.stringValue().value()')) ?
'value.stringValue() to value.stringValue().value()' : l }
File.open(fout_name, 'w') { |f| f.puts arr_out }
end
Because you are reading code files, they will not be so large that reading them all at once into memory will be a problem.
Example
First, we'll construct an input file:
array = ["My dbg_printfs was a value.stringValue() as well.",
"Her dbg_printfs was a value.stringValue() but not " +
"a value.stringValue().value()",
"value.stringValue() is one of my favorites"]
fin_name = 'fin'
fout_name = 'fout'
File.open(fin_name, 'w') { |f| f.puts array }
We can confirm its contents with:
File.readlines(fin_name).map { |l| puts l }
Now try it:
filter_array(fin_name, fout_name)
Read the output file to see if it worked:
File.readlines(fout_name).map { |l| puts l }
#=> value.stringValue() to value.stringValue().value()
# Her dbg_printfs was a value.stringValue() but not a value.stringValue().value()
# value.stringValue() is one of my favorites
It looks OK.
Explanation
def filter_array(fin_name, fout_name)
arr_in = File.readlines(fin_name)
arr_out = arr_in.map { |l| (l.include?('dbg_printfs') &&
l.include?('value.stringValue()') &&
!l.include?('value.stringValue().value()')) ?
'value.stringValue() to value.stringValue().value()' : l }
File.open(fout_name, 'w') { |f| f.puts arr_out }
end
For the above example,
arr_in = File.readlines('fin')
#=> ["My dbg_printfs was a value.stringValue() as well.\n",
# "Her dbg_printfs was a value.stringValue() but not a value.stringValue().value()\n",
# "value.stringValue() is one of my favorites\n"]
The first element of arr_in passed to map is:
l = "My dbg_printfs] was a value.stringValue() as well."
We have
l.include?('dbg_printfs') #=> true
l.include?('value.stringValue()') #=> true
!l.include?('value.stringValue().value()') #=> true
so that element is mapped to:
"value.stringValue() to value.stringValue().value()"
Neither of the other two elements are replaced by this string, because
!l.include?('value.stringValue().value()') #=> false
and
l.include?('dbg_printfs') #=> false
respectively. Hence,
arr_out = arr_in.map { |l| (l.include?('dbg_printfs') &&
l.include?('value.stringValue()') &&
!l.include?('value.stringValue().value()')) ?
'value.stringValue() to value.stringValue().value()' : l }
#=> ["value.stringValue() to value.stringValue().value()",
# "Her dbg_printfs was a value.stringValue() but not a value.stringValue().value()\n",
# "value.stringValue() is one of my favorites\n"]
The final step is writing arr_out to the output file.
is there any way to create variables in Ruby with dynamic names?
I'm reading a file and when I find a string, generates a hash.
e.g.
file = File.new("games.log", "r")
file.lines do |l|
l.split do |p|
if p[1] == "InitGame"
Game_# = Hash.new
end
end
end
How could I change # in Game_# to numbers (Game_1, Game_2, ...)
You can do it with instance variables like
i = 0
file.lines do |l|
l.split do |p|
if p[1] == "InitGame"
instance_variable_set("#Game_#{i += 1}", Hash.new)
end
end
end
but you should use an array as viraptor says. Since you seem to have just a new hash as the value, it can be simply
i = 0
file.lines do |l|
l.split do |p|
if p[1] == "InitGame"
i += 1
end
end
end
Games = Array.new(i){{}}
Games[0] # => {}
Games[1] # => {}
...
Why use separate variables? It seems like you just want Game to be a list with the values appended to it every time. Then you can reference them with Game[0], Game[1], ...
If you really want dynamic variable names, may be you can use a Hash, than your can set the key dynamic
file = File.new("games.log", "r")
lines = {}
i = 0
file.lines do |l|
l.split do |p|
if p[1] == "InitGame"
lines[:"Game_#{i}"] = Hash.new
i = i + 1
end
end
end