patternrubyModerate
Counting words / lines in Ruby
Viewed 0 times
wordscountinglinesruby
Problem
I solved this problem in Ruby:
Write an utility that takes 3 command-line parameters P1, P2 and P3.
P3 is OPTIONAL (see below) P1 is always a file path/name. P2 can take
the values:
Only P2 is “find”, then P3 is relevant/needed, otherwise it is not.
So, the utility does the following:
My solution looks like this:
```
#!/usr/bin/env ruby
def print_usage
puts "Usage: #{$0} words|lines"
puts " #{$0} find "
end
class LineCounter
# Initialize instance variables
def initialize
@line_count = 0
end
def process(line)
@line_count += 1
end
def print_result
puts "#{@line_count} lines"
end
end
class WordCounter
# Initialize instance variables
def initialize
@word_count = 0
end
def process(line)
@word_count += line.scan(/\w+/).size
end
def print_result
puts "#{@word_count} words"
end
end
class WordMatcher
# Initialize instance variables, using constructor parameter
def initialize(word_to_find)
@matches = []
@word_to_find = word_to_find
end
def process(line)
if line.scan(/#{@word_to_find}/).size > 0
@matches << line
end
end
def print_result
@matches.each { |line|
puts line
}
end
end
# Main program
if __FILE__ == $PROGRAM_NAME
processor = nil
# Try to find a line-processor
if ARGV.length == 2
if ARGV[1] == "lines"
processor = LineCounter.new
elsif ARGV[1] == "words"
processor = WordCounter.new
end
elsif ARGV.length == 3 && ARGV[1] == "find"
word_to_find = ARGV[2]
processor = WordMatcher.new(word_to_find)
end
if not processor
# Print usage and exit if no processor found
print_usage
exit 1
else
# Process the lines and print result
Write an utility that takes 3 command-line parameters P1, P2 and P3.
P3 is OPTIONAL (see below) P1 is always a file path/name. P2 can take
the values:
- “lines”
- “words”
- “find”
Only P2 is “find”, then P3 is relevant/needed, otherwise it is not.
So, the utility does the following:
- If P2 is “rows” it says how many lines it has
- If P2 is “words” it says how many words it has (the complete file)
- If P2 is “find” it prints out the lines where P3 is present
My solution looks like this:
```
#!/usr/bin/env ruby
def print_usage
puts "Usage: #{$0} words|lines"
puts " #{$0} find "
end
class LineCounter
# Initialize instance variables
def initialize
@line_count = 0
end
def process(line)
@line_count += 1
end
def print_result
puts "#{@line_count} lines"
end
end
class WordCounter
# Initialize instance variables
def initialize
@word_count = 0
end
def process(line)
@word_count += line.scan(/\w+/).size
end
def print_result
puts "#{@word_count} words"
end
end
class WordMatcher
# Initialize instance variables, using constructor parameter
def initialize(word_to_find)
@matches = []
@word_to_find = word_to_find
end
def process(line)
if line.scan(/#{@word_to_find}/).size > 0
@matches << line
end
end
def print_result
@matches.each { |line|
puts line
}
end
end
# Main program
if __FILE__ == $PROGRAM_NAME
processor = nil
# Try to find a line-processor
if ARGV.length == 2
if ARGV[1] == "lines"
processor = LineCounter.new
elsif ARGV[1] == "words"
processor = WordCounter.new
end
elsif ARGV.length == 3 && ARGV[1] == "find"
word_to_find = ARGV[2]
processor = WordMatcher.new(word_to_find)
end
if not processor
# Print usage and exit if no processor found
print_usage
exit 1
else
# Process the lines and print result
Solution
Some notes:
I'd write:
- Those counter classes are probably overkill, keep it simple.
- Ruby is an OOP language, but it's not necessary to create a bunch of classes for simple scripts like this.
- Idiomatic:
if not x->if !x
- Idiomatic:
{ ... }for one-line blocks,do/endfor multi-line.
I'd write:
fail("Usage: #{0} PATH (lines|words|find REGEXP)") unless ARGV.size >= 2
path, mode, optional_regexp = ARGV
open(path) do |fd|
case mode
when "lines"
puts(fd.lines.count)
when "words"
puts(fd.lines.map { |line| line.split.size }.reduce(0, :+))
when "find"
if optional_regexp
fd.lines.each { |line| puts(line) if line.match(optional_regexp) }
else
fail("mode find requires a REGEXP argument")
end
else
fail("Unknown mode: #{mode}")
end
endCode Snippets
fail("Usage: #{0} PATH (lines|words|find REGEXP)") unless ARGV.size >= 2
path, mode, optional_regexp = ARGV
open(path) do |fd|
case mode
when "lines"
puts(fd.lines.count)
when "words"
puts(fd.lines.map { |line| line.split.size }.reduce(0, :+))
when "find"
if optional_regexp
fd.lines.each { |line| puts(line) if line.match(optional_regexp) }
else
fail("mode find requires a REGEXP argument")
end
else
fail("Unknown mode: #{mode}")
end
endContext
StackExchange Code Review Q#41480, answer score: 15
Revisions (0)
No revisions yet.