I have mac addresses in mac1.txt and mac2.txt and I wanted to do something like this:
v = File.open("/RubyDev/sort/mac1.txt",'r').each_line do |a|
w = File.open("/RubyDev/sort/mac2.txt",'r').each_line do |b|
if w in v
puts w
end
end
end
Thanks in advance for your assistance!
EDIT: That first version below is actually pretty terrible. Here's a better version:
lines = []
File.open("mac1.txt",'r').each_line do |a|
lines.push(a.rstrip!)
end
File.open("mac2.txt",'r').each_line do |b|
if lines.include?(b.rstrip!)
puts b
end
end
I think what you're looking for is something like this:
File.open("mac1.txt",'r').each_line do |a|
File.open("mac2.txt",'r').each_line do |b|
if a == b
puts b
end
end
end
Is that correct? If not, could you give more background about the issue and what you're trying to accomplish?
To get all the common lines between two files, you can use File#readlines to access all the lines in the file as an array. Keep in mind that they will still have newlines ("\n") appended, so you'll need to remove them with String#chomp. The easiest way to do this is to map the array that readlines gives you, like this:
common_macs = File.open("mac1.txt").readlines.map(&:chomp) &
File.open("mac2.txt").readlines.map(&:chomp)
I am still trying to learn Ruby, so this is unlikely a good solution, but it is a possibility. It reads the contents of the first file into a hash and then checks the contents of the second against it. I think it would be reasonably efficient (well ... unless the first file is too big to fit nicely in memory).
lines = Hash.new
File.open( "mac1.txt", 'r' ).each_line do |l|
lines[l] = true
end
File.open( "mac2.txt", 'r' ).each_line do |l|
if ( lines[l] == true )
puts l
end
end
Edit For completeness, here is the very succinct version as suggested in the comments by Mark Thomas with the white space removal suggested by Gavin Anderegg. Ruby is a sweet language.
lines = Hash.new
File.open( "mac1.txt", 'r' ).each_line {|l| lines[l.strip!] = true}
File.open( "mac2.txt", 'r' ).each_line {|l| puts l if lines[l.strip!]}
lines = {}
File.open("mac1.txt").each_line {|l| lines[l.chomp] = true}
File.open("mac2.txt").each_line {|l| puts l if lines[l.chomp]}
Related
This is a part of my file:
project(':facebook-android-sdk-3-6-0').projectDir = new File('facebook-android-sdk-3-6-0/facebook-android-sdk-3.6.0/facebook')
project(':Forecast-master').projectDir = new File('forecast-master/Forecast-master/Forecast')
project(':headerListView').projectDir = new File('headerlistview/headerListView')
project(':library-sliding-menu').projectDir = new File('library-sliding-menu/library-sliding-menu')
I need to extract the names of the libs. This is my ruby function:
def GetArray
out_file = File.new("./out.txt", "w")
File.foreach("./file.txt") do |line|
l=line.scan(/project\(\'\:(.*)\'\).projectDir/)
File.open(out_file, "w") do |f|
l.each do |ch|
f.write("#{ch}\n")
end
end
puts "#{l} "
end
end
My function returns this:
[]
[["CoverFlowLibrary"]]
[["Android-RSS-Reader-Library-master"]]
[["library"]]
[["facebook-android-sdk-3-6-0"]]
[["Forecast-master"]]
My problem is that I find nothing in out_file. How can I write to a file? Otherwise, I only need to get the name of the libs in the file.
Meditate on this:
"project(':facebook-android-sdk-3-6-0').projectDir'".scan(/project\(\'\:(.*)\'\).projectDir/)
# => [["facebook-android-sdk-3-6-0"]]
When scan sees the capturing (...), it will create a sub-array. That's not what you want. The knee-jerk reaction is to flatten the resulting array of arrays but that's really just a band-aid on the code because you chose the wrong method.
Instead consider this:
"project(':facebook-android-sdk-3-6-0').projectDir'"[/':([^']+)'/, 1]
# => "facebook-android-sdk-3-6-0"
This is using String's [] method to apply a regular expression with a capture and return that captured text. No sub-arrays are created.
scan is powerful and definitely has its place, but not for this sort of "find one thing" parsing.
Regarding your code, I'd do something like this untested code:
def get_array
File.new('./out.txt', 'w') do |out_file|
File.foreach('./file.txt') do |line|
l = line[/':([^']+)'/, 1]
out_file.puts l
puts l
end
end
end
Methods in Ruby are NOT camelCase, they're snake_case. Constants, like classes, start with a capital letter and are CamelCase. Don't go all Java on us, especially if you want to write code for a living. So GetArray should be get_array. Also, don't start methods with "get_", and don't call it array; Use to_a to be idiomatic.
When building a regular expression start simple and do your best to keep it simple. It's a maintainability thing and helps to reduce insanity. /':([^']+)'/ is a lot easier to read and understand, and accomplishes the same as your much-too-complex pattern. Regular expression engines are greedy and lazy and want to do as little work as possible, which is sometimes totally evil, but once you understand what they're doing it's possible to write very small/succinct patterns to accomplish big things.
Breaking it down, it basically says "find the first ': then start capturing text until the next ', which is what you're looking for. project( can be ignored as can ).projectDir.
And actually,
/':([^']+)'/
could really be written
/:([^']+)'/
but I felt generous and looked for the leading ' too.
The problem is that you're opening the file twice: once in:
out_file = File.new("./out.txt", "w")
and then once for each line:
File.open(out_file, "w") do |f| ...
Try this instead:
def GetArray
File.open("./out.txt", "w") do |f|
File.foreach("./file.txt") do |line|
l=line.scan(/project\(\'\:(.*)\'\).projectDir/)
l.each do |ch|
f.write("#{ch}\n")
end # l.each
end # File.foreach
end # File.open
end # def GetArray
I am trying to replace characters in a string with a shift in the ord by some number. I am thinking the best way to do this is with regex, but running into some problems.
This is the flawed code I do have
def cipher(coded_message)
coded_message=coded_message.downcase.split("")
new_message=[]
coded_message.each do |x|
x=x.gsub(/[a-d][e-z]/, '\1x.ord+22\2x.ord-4')
new_message<<x
end
p new_message.join
end
I know that my problem is with the regex and probably the replacement text, but not sure where to go on this one. Any help would be appreciated.
Ok so I took a different approach to solving your problem. Here is a solution which doesn't involve a regex, and is very flexible.
def cipher(coded_message)
new_message=[]
coded_message.downcase.each_char do |x|
case x
when ("a".."d")
new_message << (x.ord+22).chr
when ("e".."z")
new_message << (x.ord-4).chr
end
end
new_message.join
end
cipher("Code this string")
#=> "ykzapdeoopnejc"
Not much point coding a message if you can't decode it:
#code_key = 123.times.with_object({}) do |i,h|
c = i.chr
h[c] =
case c
when /[a-dA-D]/
(i+22).chr
when /[e-zE-Z]/
(i-4).chr
else
c
end
end
#decode_key = #code_key.invert
def code(message)
#code_key.values_at(*message.chars).join
end
def decode(message)
#decode_key.values_at(*message.chars).join
end
message = "Is 42 an important number?"
coded_message = code(message) # => "Eo 42 wj eilknpwjp jqixan?"
decoded_message = decode(coded_message) # => "Is 42 an important number?"
I wrote the following script to read a CSV file:
f = File.open("aFile.csv")
text = f.read
text.each_line do |line|
if (f.eof?)
puts "End of file reached"
else
line_num +=1
if(line_num < 6) then
puts "____SKIPPED LINE____"
next
end
end
arr = line.split(",")
puts "line number = #{line_num}"
end
This code runs fine if I take out the line:
if (f.eof?)
puts "End of file reached"
With this line in I get an exception.
I was wondering how I can detect the end of file in the code above.
Try this short example:
f = File.open(__FILE__)
text = f.read
p f.eof? # -> true
p text.class #-> String
With f.read you read the whole file into text and reach EOF.
(Remark: __FILE__ is the script file itself. You may use you csv-file).
In your code you use text.each_line. This executes each_line for the string text. It has no effect on f.
You could use File#each_line without using a variable text. The test for EOF is not necessary. each_line loops on each line and detects EOF on its own.
f = File.open(__FILE__)
line_num = 0
f.each_line do |line|
line_num +=1
if (line_num < 6)
puts "____SKIPPED LINE____"
next
end
arr = line.split(",")
puts "line number = #{line_num}"
end
f.close
You should close the file after reading it. To use blocks for this is more Ruby-like:
line_num = 0
File.open(__FILE__) do | f|
f.each_line do |line|
line_num +=1
if (line_num < 6)
puts "____SKIPPED LINE____"
next
end
arr = line.split(",")
puts "line number = #{line_num}"
end
end
One general remark: There is a CSV library in Ruby. Normally it is better to use that.
https://www.ruby-forum.com/topic/218093#946117 talks about this.
content = File.read("file.txt")
content = File.readlines("file.txt")
The above 'slurps' the entire file into memory.
File.foreach("file.txt") {|line| content << line}
You can also use IO#each_line. These last two options do not read the entire file into memory. The use of the block makes this automatically close your IO object as well. There are other ways as well, IO and File classes are pretty feature rich!
I refer to IO objects, as File is a subclass of IO. I tend to use IO when I don't really need the added methods from File class for the object.
In this way you don't need to deal with EOF, Ruby will for you.
Sometimes the best handling is not to, when you really don't need to.
Of course, Ruby has a method for this.
Without testing this, it seems you should perform a rescue rather than checking.
http://www.ruby-doc.org/core-2.0/EOFError.html
file = File.open("aFile.csv")
begin
loop do
some_line = file.readline
# some stuff
end
rescue EOFError
# You've reached the end. Handle it.
end
In Ruby, I have an array of simple values (possible encodings):
encodings = %w[ utf-8 iso-8859-1 macroman ]
I want to keep reading a file from disk until the results are valid. I could do this:
good = encodings.find{ |enc| IO.read(file, "r:#{enc}").valid_encoding? }
contents = IO.read(file, "r:#{good}")
...but of course this is dumb, since it reads the file twice for the good encoding. I could program it in gross procedural style like so:
contents = nil
encodings.each do |enc|
if (s=IO.read(file, "r:#{enc}")).valid_encoding?
contents = s
break
end
end
But I want a functional solution. I could do it functionally like so:
contents = encodings.map{|e| IO.read(f, "r:#{e}")}.find{|s| s.valid_encoding? }
…but of course that keeps reading files for every encoding, even if the first was valid.
Is there a simple pattern that is functional, but does not keep reading the file after a the first success is found?
If you sprinkle a lazy in there, map will only consume those elements of the array that are used by find - i.e. once find stops, map stops as well. So this will do what you want:
possible_reads = encodings.lazy.map {|e| IO.read(f, "r:#{e}")}
contents = possible_reads.find {|s| s.valid_encoding? }
Hopping on sepp2k's answer: If you can't use 2.0, lazy enums can be easily implemented in 1.9:
class Enumerator
def lazy_find
self.class.new do |yielder|
self.each do |element|
if yield(element)
yielder.yield(element)
break
end
end
end
end
end
a = (1..100).to_enum
p a.lazy_find { |i| i.even? }.first
# => 2
You want to use the break statement:
contents = encodings.each do |e|
s = IO.read( f, "r:#{e}" )
s.valid_encoding? and break s
end
The best I can come up with is with our good friend inject:
contents = encodings.inject(nil) do |s,enc|
s || (c=File.open(f,"r:#{enc}").valid_encoding? && c
end
This is still sub-optimal because it continues to loop through encodings after finding a match, though it doesn't do anything with them, so it's a minor ugliness. Most of the ugliness comes from...well, the code itself. :/
I'm using ruby's File to open and read in a text file inside of a rake
task. Is there a setting where I can specify that I want the first line of
the file skipped?
Here's my code so far:
desc "Import users."
task :import_users => :environment do
File.open("users.txt", "r", '\r').each do |line|
id, name, age, email = line.strip.split(',')
u = User.new(:id => id, :name => name, :age => age, :email => email)
u.save
end
end
I tried line.lineno and also doing File.open("users.txt", "r", '\r').each do |line, index| and next if index == 0 but have not had any luck.
Change each to each_with_index do |line, index| and next if index == 0 will work.
function drop(n) will remove n lines from the beginning:
File.readlines(filename).drop(1).each do |line|
puts line
end
It will read the whole file into an array and remove first n lines. If you are reading whole file anyway it's probably the most elegant solution.
When reading larger files foreach will be more efficient, as it doesn't read all data into memory:
File.foreach(filename).with_index do |line, line_num|
next if line_num == 0
puts line
end
File.open("users.txt", "r", '\r') do |file|
lines = file.lines # an enumerator
lines.next #skips first line
lines.each do |line|
puts line # do work
end
end
Making use of an enumerator, which 'remembers' where it is.
You probably really want to use csv:
CSV.foreach("users.txt", :headers, :header_converters => :symbol, :col_sep => ',') do |row|
User.new(row).save
end
File.readlines('users.txt')[1..-1].join()
Works good too.
if you want to keep the file as IO the whole time (no array conversions) and you plan on using the data in the first line:
f = File.open('users.txt', 'r')
first_line = f.gets
body = f.readlines
More likely though, what you want is handled by CSV or FasterCSV as others have pointed out. My favorite way to handle files with a header line is to do:
FasterCSV.table('users.txt')
Since a few answers (no longer ?) work in Ruby 1.9.3, here a working sample of the three best methods
# this line must be dropped
puts "using drop"
File.readlines(__FILE__).drop(1).each do |line|
puts line
end
puts ""
puts "using a range"
File.readlines(__FILE__)[1..-1].each do |line|
puts line
end
puts ""
puts "using enumerator"
File.readlines(__FILE__).each do |file, w|
lines = file.lines # an enumerator
lines.next #skips first line
lines.each do |line|
puts line
end
end
The OP said lineno didn't work for them, but I'm guessing it wasn't applied in the correct way. There's lots of ways achieve what the OP is asking for, but using lineno might help you shorten up your code without having to use readlines, which is sometimes too memory intensive.
From the 1.9.3 docs
f = File.new("testfile")
f.each {|line| puts "#{f.lineno}: #{line}" }
produces:
1: This is line one
2: This is line two
3: This is line three
4: And so on...
Note that is a method you can call from the file object, but not the object yielded to the block.
2: require 'pry'; binding.pry
=> 3: f.each {|line| puts line.lineno }
[1] pry(#<SomeFile>)> line.lineno
NoMethodError: undefined method `lineno' for #<String:0x00007fa7d682b920>
You can find the same example with identical code in docs for the latest stable version of Ruby today (2.5.1).
So going off the example, the code might look like
f = File.new("testfile")
o = File.open("output.txt", w)
f.each do |line|
next if f.lineno == 1
o << line
end