Skip to content

Instantly share code, notes, and snippets.

@mattsan
Last active May 25, 2019 12:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattsan/8350a38bcb8fd354a10e11f19abb1c28 to your computer and use it in GitHub Desktop.
Save mattsan/8350a38bcb8fd354a10e11f19abb1c28 to your computer and use it in GitHub Desktop.
[練習] wc (の機能の一部)を C++ で実装してみた
defmodule ExCount.CLI do
@opts [
strict: [only_line: :boolean],
aliases: [l: :only_line]
]
def main(args) do
args
|> OptionParser.parse(@opts)
|> show_counts()
end
def show_counts({options, [], []}) do
only_line = Keyword.get(options, :only_line, false)
count = ExCount.count_io(:stdio)
show_count(count, only_line)
:io.nl()
end
def show_counts({options, filenames, []}) do
only_line = Keyword.get(options, :only_line, false)
total =
filenames
|> Enum.reduce(%ExCount{}, fn filename, acc ->
{:ok, count} = File.open(filename, [:read], &ExCount.count_io(&1))
show_count(count, only_line)
IO.puts(" #{filename}")
%ExCount{
lines: acc.lines + count.lines,
words: acc.words + count.words,
chars: acc.chars + count.chars
}
end)
if Enum.count(filenames) > 1 do
show_count(total, only_line)
IO.puts(" total")
end
end
def show_count(%ExCount{lines: lines}, true) do
:io.format('~8B', [lines])
end
def show_count(%ExCount{lines: lines, words: words, chars: chars}, false) do
:io.format('~8B~8B~8B', [lines, words, chars])
end
end
defmodule ExCount do
defstruct lines: 0, words: 0, chars: 0
defguardp is_space(c) when c in ' \r\t'
def count_io(io) do
count_io(io, %ExCount{}, false)
end
def count_io(io, wc, word) do
case IO.read(io, 1) do
:eof ->
wc
"\n" ->
count_io(io, %{wc | chars: wc.chars + 1, lines: wc.lines + 1}, false)
<<c>> when is_space(c) ->
count_io(io, %{wc | chars: wc.chars + 1}, false)
_ when not word ->
count_io(io, %{wc | chars: wc.chars + 1, words: wc.words + 1}, true)
_ ->
count_io(io, %{wc | chars: wc.chars + 1}, word)
end
end
end
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cctype>
#include <cstring>
struct Count {
int lines;
int words;
int chars;
Count() : lines(0), words(0), chars(0) {}
Count(int lines, int words, int chars) : lines(lines), words(words), chars(chars) {}
Count& operator += (const Count& other) {
lines += other.lines;
words += other.words;
chars += other.chars;
return *this;
}
struct Format {
const Count& count;
bool only_line;
explicit Format(const Count& count, bool only_line) : count(count), only_line(only_line) {}
};
Format format(bool only_line = false) {
return Format(*this, only_line);
}
};
std::ostream& operator << (std::ostream& out, const Count::Format& format) {
out << std::setw(8) << format.count.lines;
if (!format.only_line) {
out
<< std::setw(8) << format.count.words
<< std::setw(8) << format.count.chars;
}
return out;
}
Count count_io(std::istream& in) {
bool word = false;
Count count;
char c;
while(in.get(c).good()) {
++count.chars;
if (c == '\n') {
++count.lines;
word = false;
} else if (std::isspace(c)) {
word = false;
} else if (!word) {
++count.words;
word = true;
}
}
return count;
}
int main(int argc, char** argv) {
bool only_line = false;
int index = 1;
if (argc > 1 && std::strcmp(argv[index], "-l") == 0) {
only_line = true;
++index;
}
if (index == argc) {
std::cout << count_io(std::cin).format(only_line) << std::endl;
} else {
int fcount = 0;
Count total;
for (; index < argc; ++index) {
std::ifstream in(argv[index]);
if (in.good()) {
Count count = count_io(in);
std::cout << count.format(only_line) << " " << argv[index] << "\n";
total += count;
} else {
std::cerr << argv[0] << ": " << argv[index] << ": open: No such file or directory" << std::endl;
}
++fcount;
}
if (fcount >= 2) {
std::cout << total.format(only_line) << " total" << std::endl;
}
}
return 0;
}
require 'optparse'
class Count
class Format
def initialize(count, only_lines = nil)
@count = count
@only_lines = only_lines
end
def to_s
if @only_lines
format('%8d', @count.lines)
else
format('%8d%8d%8d', @count.lines, @count.words, @count.chars)
end
end
end
HT = ?\t.ord
LF = ?\n.ord
CR = ?\r.ord
SP = ' '.ord
attr_accessor :lines, :words, :chars
def self.[](io_or_filename)
if io_or_filename.is_a?(IO)
count_io(io_or_filename)
else
File.open(io_or_filename) do |file|
count_io(file)
end
end
end
def self.count_io(io)
word = false
count = new
io.each_byte do |c|
count.chars += 1
if c == LF
count.lines += 1
word = false
elsif [HT, CR, SP].include?(c)
word = false
elsif !word
count.words += 1
word = true
end
end
count
end
def initialize(lines = 0, words = 0, chars = 0)
@lines = lines
@words = words
@chars = chars
end
def +(other)
Count.new(
@lines + other.lines,
@words + other.words,
@chars + other.chars
)
end
def format(only_lines = false)
Format.new(self, only_lines)
end
end
class CLI
class Options
attr_reader :files
def initialize
opts = OptionParser.new
opts.on('-l') {|v| v }
@options = {}
opts.parse!(ARGV, into: @options)
@files = ARGV.dup.freeze
end
def only_lines?
@options[:l]
end
end
def self.run
new.run
end
def initialize
@options = Options.new
end
def run
if @options.files.empty?
count_stdin
else
count_files
end
end
private
def count_stdin
puts Count[STDIN].format(@options.only_lines?)
end
def count_files
total = Count.new
@options.files.each do |filename|
count = Count[filename]
puts "#{count.format(@options.only_lines?)} #{filename}"
total += count
end
puts "#{total.format(@options.only_lines?)} total" if @options.files.size >= 2
end
end
CLI.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment