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
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}")
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.
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
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 }
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.