どぼじょのIT学習ブログ

高専卒土木女子がIT業界を目指してお勉強。

Rubyでwcコマンドを作った

lsコマンドに続き、Rubyでwcコマンドを作りました〜!
課題なのでカンニング防止のためコードは公開できないのですが、学んだことまとめます💪

目次

1.wcコマンドとは

wcコマンドは、指定したファイルの行数・単語数・バイト数を表示してくれるコマンドです🌱
f:id:mistyrinth:20190315193802p:plain
上記のとおり、fileAは7行、6単語、43バイトであることがわかります✨
7行で6単語というのは、最後に空白行があるからです。ややこしくてすみません笑
f:id:mistyrinth:20190315194028p:plain
なお、macのwcコマンドのソースコードこちらです。

2.wcコマンド成果

複数のコマンドライン引数に対応しました🎉
f:id:mistyrinth:20190315192844p:plain

オプションは-l-w-cに対応しました。
f:id:mistyrinth:20190315193003p:plain

標準入力にも対応👏
f:id:mistyrinth:20190315193101p:plain

3.学んだこと

3-1. コマンドライン引数

lsコマンドでもコマンドライン引数は扱いましたが、なんとなくで出来てしまっていました💦
wcコマンドはそうはいかなかったので、以前よりは扱えるようになったと思います。
RubyにはARGVという、コマンドライン引数を配列にしたものがあります。
例えば$ wc file1 file2ならARGV = ["file1", "file2"]となります。

3-2. 標準入力

Rubyには標準入力を扱うための変数があることがわかりました!

docs.ruby-lang.org

$stdinでもSTDINでもどちらでも良いそうです。
配列のARGVと違って変数なので、それ自体が値を持っているのではないことや、標準入力が代入されるということが注意点でした。

3-3. マルチバイト文字の単語数

これが一番苦戦したのですが、マルチバイト文字を含むファイルを指定すると単語数がずれてしまうことがありました…😭
単語数というのは、wcコマンドにおいては空白文字で区切られた文字列の数と定義されています。
man wcに書いてありました👀

A word is defined as a string of characters delimited by white space characters.
White space characters are the set of characters for which the iswspace(3) function returns true.

そしてこの空白文字の定義はiswspace関数が true であることなんです。
更に、iswspace関数が true を返す値というのは以下のとおりです。

- 空白' '
- 改頁 \f
- 改行 \n
- 復帰 \r
- 水平タブ \t
- 垂直タブ \v

ここまでは良いのですが、これらとマルチバイト文字が何の関係があるかというと、マルチバイト文字はバイト文字に変換すると、ノーブレークスペースというのが含まれていることがあるそうです😳
例えば「配列」のの字にノーブレークスペースが含まれます。

text = "配 列"
text.bytes { |b| print "0x" + b.to_s(16) + " "}
#=> 0xe9 0x85 0x8d 0x20 0xe5 0x88 0x97

配 列という文字列に対して、空白で区切った文字列の数を単語数とすると、2単語ですよね🙂
でもこれオリジナルのwcコマンドだと3が返ってくるんです…😖
をバイト文字にすると0xe9 0x85 0x8dで、このうちの0x85が iswspace 関数で true になってしまうからです。
このような目に見えないスペースをノーブレークスペースと言うそうです。
0x20は普通の半角スペースで、改行は0xa0になります。

ノーブレークスペースをカウントするために、マルチバイト文字をバイト文字列に変換し、ノーブレークスペースの数だけ単語数を増やすことになりました。
バイト文字列というのがよくわかっていなかったのですが、先頭の0xは共通みたいです😶
bytesメソッドで文字列をバイトの数値に変換できるので、それを更に16進数に変換し、0xに続けます。
UTF-8 とかの文字コード?もぼんやりとしか分かっていないので、難しかったです〜〜💀💀💀
分かりやすいサイトとかあったら教えてほしいです…。