selective replacing of printf statements - ruby

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.

Related

Filter through a text file

I want to sort through a text file and leave only a certain section. I have this text in the text file:
{
"id"=>”0000001”,
"type"=>”cashier”,
"summary"=>”Henock”,
"self"=>"https://google.com/accounts/0000001”,
"html_url"=>"https://google.com/accounts/0000001”
}
{
"id"=>”0000002”,
"type"=>”cashier”,
"summary"=>”Vic”,
"self"=>"https://google.com/accounts/0000002”,
"html_url"=>"https://google.com/accounts/0000002”
}
{
"id"=>”0000003”,
"type"=>”cashier”,
"summary"=>”Mo”,
"self"=>"https://google.com/accounts/0000003”,
"html_url"=>"https://google.com/accounts/0000003”
}
How would I sort it so that only the information with person "Mo" is shown?
This is what I tried:
somefile.readlines("filename.txt").grep /Mo}/i
but it is useless.
Code
def retrieve_block(fname, summary_target)
arr = []
File.foreach(fname) do |line|
next if line.strip.empty?
arr << line
next unless arr.size == 7
return arr.join if arr[3].match?(/\"summary\"=>\"#{summary_target}\"/)
arr = []
end
end
Example
Let's first create a file.
text =<<_
{
"id"=>"0000001",
"type"=>"cashier",
"summary"=>"Henock",
"self"=>"https://google.com/accounts/0000001",
"html_url"=>"https://google.com/accounts/0000001"
}
{
"id"=>"0000003",
"type"=>"cashier",
"summary"=>"Mo",
"self"=>"https://google.com/accounts/0000003",
"html_url"=>"https://google.com/accounts/0000003"
}
_
All of the keys and values represented in this string are surrounded with double-quotes. In the question however, many of these keys and values are surrounded by special characters that have a superficial appearance of a double quote. I have assumed that those characters would be converted to double quotes in a pre-processing step.
FName = "test"
File.write(FName, text)
#=> 325
puts retrieve_block(FName, "Mo")
{
"id"=>"0000003",
"type"=>"cashier",
"summary"=>"Mo",
"self"=>"https://google.com/accounts/0000003",
"html_url"=>"https://google.com/accounts/0000003"
}
This should work because of the consistent format of the file.
To return a hash, rather than a string, a slight modification is required.
def retrieve_block(fname, summary_target)
h = {}
File.foreach(fname) do |line|
line.strip!
next if line.empty? || line == '{'
if line == '}'
if h["summary"] == summary_target
break h
else
h = {}
end
else
k, v = line.delete('",').split("=>")
h[k] = v
end
end
end
retrieve_block(FName, "Mo")
#=> {"id"=>"0000003",
# "type"=>"cashier",
# "summary"=>"Mo",
# "self"=>"https://google.com/accounts/0000003",
# "html_url"=>"https://google.com/accounts/0000003"}

ruby How I could print without leave newline space for each line?

ruby How I could print without leave newline space for each line
this is my file
name1;name2;name3
name4;name5;name6
I have this command
File.open("text2xycff.txt", "r") do |fix|
fix.readlines.each do |line|
parts = line.chomp.split(';')
input3= zero
File.open('text2xyczzzz2.txt', 'a+') do |f|
f.puts parts[0] , parts[1], parts[2] ,input3
end
end
end
this is my output
name1
name2
name3
zero
name4
name5
name6
zero
I need to output this
name1;name2;name3;zero
name4;name5;name6;zero
Please help me whit this problem
A more minimal approach is to just append something to each line:
File.open("text2xycff.txt", "r") do |input|
File.open('text2xyczzzz2.txt', 'a+') do |output|
input.readlines.each do |line|
output.puts(line.chomp + ';zero')
end
end
end
Or if you want to actually parse things, which presents an opportunity for clean-up:
File.open("text2xycff.txt", "r") do |input|
File.open('text2xyczzzz2.txt', 'a+') do |output|
input.readlines.each do |line|
parts = line.chomp.split(/;/)
parts << 'zero'
output.puts(parts.join(';'))
end
end
end
You have two solutions.
The first one uses puts as you currently do:
File.open('yourfile.txt', 'a+') { |f|
f.puts "#{parts[0]}#{parts[1]}#{parts[2]}#{input3}"
}
The second one uses write instead of puts:
File.open('yourfile.txt', 'a+') { |f|
f.write parts[0]
f.write parts[1]
f.write parts[2]
f.write input3
}
If you call puts with comma-separated arguments, each one of them will be printed on a different line.
You can use ruby string interpolation here (http://ruby-for-beginners.rubymonstas.org/bonus/string_interpolation.html):
f.puts "#{parts[0]};#{parts[1]};#{parts[3]};#{input3}"
Try:
File.open("test_io.txt", "r") do |fix|
fix.readlines.each do |line|
File.open('new_file10.txt', 'a+') do |f|
next if line == "\n"
f.puts "#{line.chomp};zero"
end
end
end
I'm not sure why you're splitting the string by semicolon when you specified you wanted the below output. You would be better served just appending ";zero" to the end of the string rather than parsing an array.
name1;name2;name3;zero
name4;name5;name6;zero
You can specify an if statement to check for the zero value.
Example:
arr = ["name1", "name2", "name3", "zero", "name4", "name5", "name6", "zero"];
arr.each { |x|
if x != "zero" then
print x
else
puts x
end
}
Output:
name1name2name3zero
name4name5name6zero
print will print inline.
puts will print on a new line.
Just implement this logic in your code and you're good to go.

split array element before . eg li.mean-array

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.

Ruby Array Loop

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

Ruby dynamic variable name

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

Resources