Rubyでwcコマンドを作った
lsコマンドに続き、Rubyでwcコマンドを作りました〜!
課題なのでカンニング防止のためコードは公開できないのですが、学んだことまとめます💪
目次
1.wcコマンドとは
wcコマンドは、指定したファイルの行数・単語数・バイト数を表示してくれるコマンドです🌱
上記のとおり、fileA
は7行、6単語、43バイトであることがわかります✨
7行で6単語というのは、最後に空白行があるからです。ややこしくてすみません笑
なお、macのwcコマンドのソースコードはこちらです。
2.wcコマンド成果
複数のコマンドライン引数に対応しました🎉
オプションは-l
、-w
、-c
に対応しました。
標準入力にも対応👏
3.学んだこと
3-1. コマンドライン引数
lsコマンドでもコマンドライン引数は扱いましたが、なんとなくで出来てしまっていました💦
wcコマンドはそうはいかなかったので、以前よりは扱えるようになったと思います。
RubyにはARGV
という、コマンドライン引数を配列にしたものがあります。
例えば$ wc file1 file2
ならARGV = ["file1", "file2"]
となります。
3-2. 標準入力
Rubyには標準入力を扱うための変数があることがわかりました!
$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 とかの文字コード?もぼんやりとしか分かっていないので、難しかったです〜〜💀💀💀
分かりやすいサイトとかあったら教えてほしいです…。