Writing regex result into a new file - ruby

I've got a list of devices:
ipc-bei640-r-br-01
ipc-bei640-r-br-02
ipc-bei640-r-br-03
ipc-bei640-r-br-04
ipc-bei640-r-br-05
ipc-bem640-r-br-01
ipc-bem640-r-br-02
ipc-bem640-r-br-03
ipc-crg660-r-br-02
ipc-geb680-r-br-04
ipc-lgv630-r-br-01
This small little ruby script counts the lines of the file braslist.txt scans it with a regex and writes the results to a newfile called "strippedfile.txt"
lines = IO.readlines("/usr/local/bin/braslist.txt")
# Linecount is forwarded to StdOut.
puts lines.length
str = File.read('braslist.txt')
file_name = ['strippedfile.txt']
file_name.each do |file_name|
text = File.read(file_name)
new_contents = str.scan(/^ipc-(?<bng>[a-z]{3}\d{3})-r-br(?<nr>-\d{2})$/)
# open and write to a file with ruby
open('strippedfile.txt', 'w') { |f|
f.print new_contents
}
end
Now what i cant seem to fix, is in the new file "strippedfile" the results are always ["bei640", "-01"] ["bei640", "-02"] ["bei640", "-03"]
And i am trying to get all results in this format:
bei640-01
bei640-02
bei640-03
bei640-04

scan returns an array of matches, you probably want to join them:
- new_contents = str.scan(/^ipc-(?<bng>[a-z]{3}\d{3})-r-br(?<nr>-\d{2})$/)
+ new_contents = str.scan(/^ipc-(?<bng>[a-z]{3}\d{3})-r-br(?<nr>-\d{2})$/).map(&:join)
To print everything without quotes and brackets line by line:
- f.print new_contents
+ f.puts new_contents

Assuming your resultant array is
a = [["bei640", "-02"], ["bei640", "-03"]]
You can use join to get your desired result
a.map{|i| i.join } #=> ["bei640-02", "bei640-03"]
or use shortcut as mudasobwa answered
a.map(&:join) #=> ["bei640-02", "bei640-03"]

Related

Having issues searching through file and replacing

I'm having a bit of trouble searching through a file and editing certain parameters of the file. The code is below
file_names = ["#{fileNameFromUser}"]
file_names.each do |file_name|
text = File.read(file_name)
replacedcontent = text.gsub(/textToReplace/, "#{ReplaceWithThis}")
replacedcontent += text.gsub(/textToReplace2/, "#{ReplaceWithThis2}")
# To write changes to the file, use:
File.open(file_name, "w") {|file| file.puts replacedcontent}
end
so right now what it does is that it print the contents of the file twice and I can only assume its because its inside the do loop. My end goal here is that the file has textToReplace and textToReplace2 and I need it to read through the file, replaced both with whatever the user inputs and save/write changes to the file.
it print the contents of the file twice and I can only assume its because its inside the do loop
Nope, it's because you append it twice:
text = first_replacement_result
text += second_replacement_result
There's two ways to do this: one with mutation:
text.gsub!(...) # first replacement that changes `text`
text.gsub!(...) # second replacement that changes `text` again
or chained replacement:
replacedcontent = text.gsub(...).gsub(...) # two replacements one after another
You will need to re-use replacedcontent instead of concatenating it to avoid printing it twice.
file_names = ["#{fileNameFromUser}"]
file_names.each do |file_name|
text = File.read(file_name)
replacedcontent = text.gsub(/textToReplace/, "#{ReplaceWithThis}")
replacedcontent = replacedcontent.gsub(/textToReplace2/, "#{ReplaceWithThis2}")
# To write changes to the file, use:
File.open(file_name, "w") {|file| file.puts replacedcontent}
end
OR
replacedcontent = text.gsub(/textToReplace/, "#{ReplaceWithThis}").gsub(/textToReplace2/, "#{ReplaceWithThis2}")

Remove concrete string from CSV in Ruby

I got a ruby script which take XML files and create from them CSV. This CSV use semicolons as delimiter -> but, content of XML contains these tags:
- &
- <
- >
And this of course break the structure of CSV file. I need clean it up. This cleaner must be writen in Ruby. I try next code, but this complete destroy the file.
#Clean up CSV file
#Remove: & \< >
file_names = ['terms.csv']
file_names.each do |file_name|
text = File.read(file_name)
new_contents = text.gsub(/&/, " and ")
# To merely print the contents of the file, use:
puts new_contents
# To write changes to the file, use:
File.open(file_name, "w") {|file| file.puts new_contents }
end
file_names.each do |file_name|
text = File.read(file_name)
new_contents = text.gsub(/</, " < ")
puts new_contents
File.open(file_name, "w") {|file| file.puts new_contents }
end
file_names.each do |file_name|
text = File.read(file_name)
new_contents = text.gsub(/>/, " > ")
puts new_contents
File.open(file_name, "w") {|file| file.puts new_contents }
end
I never use Ruby - this is my first contact. Is there better way how to do this?
I solved it... I change CSV delimiter from ";" to "#" in FOR cycle which create a CSV file. It is not ideal solution, but it works.

Dynamic variable from string in Ruby [duplicate]

This question already has answers here:
How to dynamically create a local variable?
(4 answers)
Closed 3 years ago.
I am copying each line of a file to separate files, depending on the content. Each line begins with "foo" or "bar", and I want to read the first few characters of each line and dynamically change the file name variable.
readfile = File.open("myfile.txt", 'r')
file_foo = File.open("file1.txt", 'w')
file_bar = File.open("file2.txt", 'w')
for line in readfile
writefile = 'file_' + line[0..2]
writefile.write(line)
end
file_foo.close
file_bar.close
This throws an error, as the variable writefile refers to the string "file_foo" or "file_bar".
Suggestions for an elegant Rubyist solution? I couldn't see from the documentation how send method could be applied here if that is indeed the way to go.
Make a hash of files:
readfile = File.open("myfile.txt", 'r')
files = {
'foo' => File.open("file1.txt", 'w'),
'bar' => File.open("file2.txt", 'w')
}
for line in readfile
files[line[0..2]].write(line)
end
files.each {|k, v| v.close}
I think you are looking for eval. It will take a string and evaluate it as Ruby code in the current context. So your example becomes:
readfile = File.open("myfile.txt", 'r')
file_foo = File.open("file1.txt", 'w')
file_bar = File.open("file2.txt", 'w')
for line in readfile
eval('file_' + line[0..2]).write(line)
end
filefoo.close
filebar.close
However, you asked for a "Rubyist" approach. Using eval is certainly NOT a Rubyist approach. Nor is the use of for loops. I'll take a crack at a more Rubyist approach:
infile = "myfile.txt"
foofile = "file1.txt"
barfile = "file2.txt"
def append_to_file(path, content)
File.open(path, 'a') { |f| f << content }
end
IO.readlines(readfile).each do |line|
case line
when /^foo/
append_to_file(foofile, line)
when /^bar/
append_to_file(barfile, line)
end
end
You cannot use send because what you are trying to convert a string into is not a method but is a local variable.
From Ruby 2.1, you will be able to use Binding#local_variable_get.
for line in readfile
writefile = binding.local_variable_get(:"file_#{line[0..2]}")
writefile.write(line)
end

In Ruby- Parsing Directory and reading first row of the file

Below is the piece of code that is supposed read the directory and for each file entry prints the first row of the file. The issue is x is not visible so file is not being parsed.
Dir.foreach("C:/fileload/src") do |file_name|
x = file_name
puts x
f = File.open("C:/fileload/src/" +x)
f.readlines[1..1].each do |line|
puts line
end
end
Why are you assigning x to file_name? You can use file_name directly. And if you are only reading the first line of the file, why not try this?
#!/usr/bin/ruby
dir = "C:/fileload/src"
Dir.foreach(dir) do |file_name|
full = File.join(dir, file_name)
if File.file?(full)
f = File.open(full)
puts f.first
f.close
end
end
You should use File.join to safely combine paths in Ruby. I also checked that you are opening a file using the File.file? method.
You have no visibility issue with x. You should be using File::join or Pathname#+ to build your file paths. You should exclude non-files from consideration. You're selecting the second line, not the first with [1..1]. Here's a cleaner correct replacement for your sample code.
dir = "C:/fileload/src"
Dir.foreach(dir).
map { |fn| File.join(dir,fn) }.
select { |fn| File.file?(fn) }.
each { |fn| puts File.readlines(fn).first }

Read Certain Lines from File

Hi just getting into Ruby, and I am trying to learn some basic file reading commands, and I haven't found any solid sources yet.
I am trying to go through certain lines from that file, til the end of the file.
So in the file where it says FILE_SOURCES I want to read all the sources til end of file, and place them in a file.
I found printing the whole file, and replacing words in the file, but I just want to read certain parts in the file.
Usually you follow a pattern like this if you're trying to extract a section from a file that's delimited somehow:
open(filename) do |f|
state = nil
while (line = f.gets)
case (state)
when nil
# Look for the line beginning with "FILE_SOURCES"
if (line.match(/^FILE_SOURCES/))
state = :sources
end
when :sources
# Stop printing if you hit something starting with "END"
if (line.match(/^END/))
state = nil
else
print line
end
end
end
end
You can change from one state to another depending on what part of the file you're in.
I would do it like this (assuming you can read the entire file into memory):
source_lines = IO.readlines('source_file.txt')
start_line = source_lines.index{ |line| line =~ /SOURCE_LINE/ } + 1
File.open( 'other_file.txt', 'w' ) do |f|
f << source_lines[ start_line..-1 ].join( "\n" )
end
Relevant methods:
IO.readlines to read the lines into an array
Array#index to find the index of the first line matching a regular expression
File.open to create a new file on disk (and automatically close it when done)
Array#[] to get the subset of lines from the index to the end
If you can't read the entire file into memory, then I'd do a simpler variation on #tadman's state-based one:
started = false
File.open( 'other_file.txt', 'w' ) do |output|
IO.foreach( 'source_file.txt' ) do |line|
if started then
output << line
elsif line =~ /FILE_SOURCES/
started = true
end
end
end
Welcome to Ruby!
File.open("file_to_read.txt", "r") {|f|
line = f.gets
until line.include?("FILE_SOURCES")
line = f.gets
end
File.open("file_to_write.txt", "w") {|new_file|
f.each_line {|line|
new_file.puts(line)
}
new_file.close
}
f.close
}
IO functions have no idea what "lines" in a file are. There's no straightforward way to skip to a certain line in a file, you'll have to read it all and ignore the lines you don't need.

Resources