Last active
May 25, 2019 12:14
-
-
Save mattsan/8350a38bcb8fd354a10e11f19abb1c28 to your computer and use it in GitHub Desktop.
[練習] wc (の機能の一部)を C++ で実装してみた
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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