Ruby - Appending data in a new line without introducing an empty line - ruby

I already have one line in fd.txt and when I'm inserting three multiple lines, the first line appends right after the existing data. Here's an example:
fd.txt
This is past data.
New data
Line 1
Line 2
Line 3
When I run the following code:
open('fd.txt', 'a+') { |file|
file.puts "Line 1"
file.puts "Line 2"
file.puts "Line 3"
}
I get the following output:
This is past data.Line 1
Line 2
Line 3
But, I need Line 1 from the second line. So I add "\n" in file.puts "\nLine 1" but this adds an additional empty line right before Line 1. What update should I make to my code to get the following output:
This is past data.
Line 1
Line 2
Line 3

Not very elegant, but you could check whether the last character is a \n and add one otherwise: (I assume that you don't know if the file ends with a newline)
open('fd.txt', 'a+') do |file|
file.puts unless file.pread(1, file.size - 1) == "\n"
file.puts "Line 1"
file.puts "Line 2"
file.puts "Line 3"
end
It would be better of course to not have a missing newline in the first place.

Similar to the other proposed answer, you could do:
open('fd.txt', 'a+') do |file|
file.seek(-1, IO::SEEK_END)
file.puts unless file.read == "\n"
file.puts "Line 1"
file.puts "Line 2"
file.puts "Line 3"
end

Related

Get the first word of a file into a variable

I have a txt file and I want to extract only the first word of a line which contains the characters 'ath'.
File.open("myfile.txt").readlines.each do |line|
if line =~ /ath/
line.split.first
puts line
$line = line.chomp
puts "Ok"
else
nil
end
end
line.split.first only works if the first word of the line is a match, because when I do the same in irb:
"im here to ask someting easy".split.first
The output is 'im'.
If the first word in a line contains ath at any point
if line =~ /^\S*ath\S*/

Iterate and print the content of all files in ruby

I'm very new to the Ruby world so please bear if its a simple query.
For one of my assignments, I'm looking to read the contents of all the text files in a folder (only top level) and redirect the file contents to a single output file in a appended or merged manner.
I'm a expecting a format like below:
Output File
File Name: 1st file name
all its contents
====================================
File Name: 2nd file name
all its contents
====================================
File Name: 3rd file name
all its contents
====================================
....
....
====================================
I managed to write the below script but the output file is empty. Any suggestions please.
File.open('C:\Users\darkop\Desktop\final_output.txt','a') do |final|
#files = Dir.glob("D:\text\*.txt")
for file in #files
text = File.open(file, 'r').read.sub(/#$/?\z/, $/)
text.each_line do |line|
puts "File Name:"#{file}
puts
final << line
puts "=" * 20
end
end
end
Also, is it possible to redirect the output in aforementioned format to a word document instead of a text file ?
Many thanks.
This should work.
The file name was empty because you have puts "File Name:"#{file}. This way #{file} doesn't get interpolated, because it isn't inside the double quotation marks.
Also, you didn't get the contents of the file because you just used puts, instead of puts line, which is what you want.
File.open('C:\Users\darkop\Desktop\final_output.txt','a') do |final|
#files = Dir.glob("D:\text\*.txt")
for file in #files
text = File.open(file, 'r').read.sub(/#$/?\z/, $/)
text.each_line do |line|
puts "File Name: #{file}"
puts
puts line
final << line
puts "=" * 20
end
end
end
-EDIT-
Since you are new to Ruby, it's better to use an each loop, instead of the for .. in loop. Also, just specify the output name with a .doc extension for a Word document.
File.open('C:\Users\darkop\Desktop\final_output.doc','a') do |final|
#files = Dir.glob("D:\text\*.txt")
#files.each do |file|
text = File.open(file, 'r').read.sub(/#$/?\z/, $/)
text.each_line do |line|
puts "File Name: #{file}"
puts
puts line
final << line
puts "=" * 20
end
end
end

Ruby Tempfile - line match and remove duplicate lines

Further to stackoverflow question in the link below:
ruby match string or space/tab at the beginning of a line and insert uniq lines to a file
enter link description here
I have this files - ./files_tmp/60416.log:
AAAAAA555
AAAAAA555
BBBBBB
CCCCC
AAAAAA434343
AAAAAA434343
./files_tmp/60417.log
AAAAAA55544
AAAAAA55544
BBBBBB
CCCCC
AAAAAA434343
AAAAAA434343
I have this code:
files = Dir["./files_tmp/*.log"]
files.each do |file_name|
puts file_name if !File.directory? file_name
Tempfile.open do |temp|
File.open(file_name) do |input|
input.each_line do |line|
if line.match(/AAAAAA/) || (line.match(/^\t/) and tabs)
puts "found a line #{line}"
temp.write(line.lstrip!)
end
end
end
File.open("./temp.log", "a") do |file|
temp.rewind
file.write(temp.readlines.uniq.join(""))
end
end
end
the result of puts "found a line #{line}" is below, but I expected it will print only the lines with AAAAAA
./files_tmp/60416.log
found a line AAAAAA555
found a line AAAAAA555
found a line BBBBBB
found a line CCCCC
found a line AAAAAA434343
found a line AAAAAA434343
./files_tmp/60417.log
found a line AAAAAA55544
found a line AAAAAA55544
found a line BBBBBB
found a line CCCCC
found a line AAAAAA434343
found a line AAAAAA434343
I can see duplicate lines in the temp file ./temp.log and not all the lines with the lines AAAAAA
AAAAAA434343
AAAAAA434343
I expected to :
AAAAAA555
AAAAAA434343
AAAAAA55544
And I wonder why ?
I am using file.write(temp.readlines.uniq.join("")) instead of file.write(temp.readlines.uniq) because the result will be :
["AAAAAA434343\n"]
it will be great to understand rewind purpose, what is it for?
Thanks for your help !
You do not need to mess with Tempfile. Just collect what you want and afterwards write everything into the destination file:
result = Dir["./files_tmp/*.log"].each_with_object([]) do |file_name, lines|
next if File.directory? file_name # skip dirs
File.readlines(file_name) do |line|
next unless line =~ /AAAAAA/
puts "found a line #{line}"
lines |= [line.lstrip!] # append if and only it’s uniq
end
end
File.write("./temp.log", result.join($/)) # join with OS-aware line sep

Ruby - Reading a file causes an extra line while printing

How can I avoid a new line when I use puts line + "test"
Example code:
File.open("test.txt", "r") do |f|
f.each_line do |line|
puts line + "test" #=>line1\ntest
#puts "test" + line #=> testline1
end
end
When I use:
puts "test" + line`
It shows:
testline1
(line1 being the only thing in the test.txt)
However,
puts line + "test"
looks like:
test
line1
Is there anyway of stopping it from producing the extra line?
If you want to strip out the newline, use String#chomp to take care of it.
http://apidock.com/ruby/v1_9_3_392/String/chomp
puts line.chomp + "test"
Use String#strip to strip out all the leading and trailing whitespace characters (including new line):
puts line.strip + "test"
# => line1test
To delete only the trailing whitespaces, you can use String#rstrip:
puts line.rstrip + "test"
# => line1test

Building multi-line strings, programmatically, in Ruby

Here's something I often do when programming:
code = ''
code << "next line of code #{something}" << "\n"
code << "another line #{some_included_expression}" << "\n"
Is there some better way than having << "\n" or + "\n" on every line? This seems quite inefficient.
I'm interested in Ruby solutions, in particular. I'm thinking something like
code = string.multiline do
"next line of code #{something}"
"another line #{some_included_expression}"
end
If you're looking to build a block of text, the easy way to do it is to just use the % operator. For example:
code = %{First line
second line
Third line #{2 + 2}}
'code' will then be
"First line\n second line\n Third line 4"
This would be one way:
code = []
code << "next line of code #{something}"
code << "another line #{some_included_expression}"
code.join("\n")
Use <<- operator:
code = <<-CODE
var1 = "foo"
var2 = "bar"
CODE
It would work for you to just embed ...\n" in your strings, I suppose. Here is a fun way to do it:
class String
def / s
self << s << "\n"
end
end
then
f = "" # => ""
f / 'line one' # => "line one\n"
f / 'line two' # => "line one\nline two\n"
f / 'line three' # => "line one\nline two\nline three\n"
This would enable something like:
"" / "line 1" / "line 2" / "line 3" # => "line 1\nline 2\nline 3\n"
Or even:
f/
"line one"/
"line two"/
"line three" # => "line one\nline two\nline three\n"
Here's a method presented here:
str = <<end.margin
|This here-document has a "left margin"
|at the vertical bar on each line.
|
| We can do inset quotations,
| hanging indentions, and so on.
end
This is accomplished by using this:
class String
def margin
arr = self.split("\n") # Split into lines
arr.map! {|x| x.sub!(/\s*\|/,"")} # Remove leading characters
str = arr.join("\n") # Rejoin into a single line
self.replace(str) # Replace contents of string
end
end
I guess the question with this is: does the lack of portability / presence of monkey patching make this solution bad.
What's wrong with:
code = "next line of code #{something}\n"+
"another line #{some_included_expression}"
You could place your multi-line text in a file, and use ERB to parse it (note ERB is included with Ruby)
require 'erb'
multi_line_string = File.open("multi_line_string.erb", 'r').read
template = ERB.new(multi_line_string)
template.result(binding)
(ERB can access variables from a Binding, an object that provides access to the instance methods and variables that are owned by another object. By setting it to "binding" it points to itself)
Documentation here.

Resources