言語処理100本ノック 2015の第2章: UNIXコマンドの基礎の10問です。
10. 行数のカウント
行数をカウントせよ.確認にはwcコマンドを用いよ.
gista7b27f35e5b111f979022b367ef696c4
# wc hightemp.txt 24 48 813 hightemp.txt
ReadLine()
で一行ずつ読み込み、読み終わった時点の行数を出力させました。
11. タブをスペースに置換
タブ1文字につきスペース1文字に置換せよ.確認にはsedコマンド,trコマンド,もしくはexpandコマンドを用いよ.
gist848871be78390be2901e02908051ccc7
# sed 's/\t/ /g' ../data/hightemp.txt 高知県 江川崎 41 2013-08-12 埼玉県 熊谷 40.9 2007-08-16 岐阜県 多治見 40.9 2007-08-16 山形県 山形 40.8 1933-07-25 山梨県 甲府 40.7 2013-08-10 和歌山県 かつらぎ 40.6 1994-08-08 静岡県 天竜 40.6 1994-08-04 山梨県 勝沼 40.5 2013-08-10 埼玉県 越谷 40.4 2007-08-16 群馬県 館林 40.3 2007-08-16 群馬県 上里見 40.3 1998-07-04 愛知県 愛西 40.3 1994-08-05 千葉県 牛久 40.2 2004-07-20 静岡県 佐久間 40.2 2001-07-24 愛媛県 宇和島 40.2 1927-07-22 山形県 酒田 40.1 1978-08-03 岐阜県 美濃 40 2007-08-16 群馬県 前橋 40 2001-07-24 千葉県 茂原 39.9 2013-08-11 埼玉県 鳩山 39.9 1997-07-05 大阪府 豊中 39.9 1994-08-08 山梨県 大月 39.9 1990-07-19 山形県 鶴岡 39.9 1978-08-03 愛知県 名古屋 39.9 1942-08-02
strings.Replace()
を使ってもいいかと思いましたが、rune
単位で一文字ずつ読み込み、tabだったら変換する方式としました。
ファイル終端の判別は、io.EOF
はerror型でrune
と比較できないので、NULL文字で判断しています。
12. 1列目をcol1.txtに,2列目をcol2.txtに保存
各行の1列目だけを抜き出したものをcol1.txtに,2列目だけを抜き出したものをcol2.txtとしてファイルに保存せよ.確認にはcutコマンドを用いよ.
gist930b77e110065c0d74170d39dd9e1e85
// 題意に合わせるにはさらにリダイレクトして出力する必要がありますが、さらにcatするのも冗長なので標準出力にしました。 # cut -f 1 ../data/hightemp.txt 高知県 埼玉県 岐阜県 山形県 山梨県 和歌山県 静岡県 山梨県 埼玉県 群馬県 群馬県 愛知県 千葉県 静岡県 愛媛県 山形県 岐阜県 群馬県 千葉県 埼玉県 大阪府 山梨県 山形県 愛知県 # cut -f 2 ../data/hightemp.txt 江川崎 熊谷 多治見 山形 甲府 かつらぎ 天竜 勝沼 越谷 館林 上里見 愛西 牛久 佐久間 宇和島 酒田 美濃 前橋 茂原 鳩山 豊中 大月 鶴岡 名古屋
filepath
パッケージで入力と同じディレクトリに出力するようにしました。
13. col1.txtとcol2.txtをマージ
12で作ったcol1.txtとcol2.txtを結合し,元のファイルの1列目と2列目をタブ区切りで並べたテキストファイルを作成せよ.確認にはpasteコマンドを用いよ.
gista6f97b6d6ad9b9e4808fae91095e1d20
# paste ../data/col1.txt ../data/col2.txt 高知県 江川崎 埼玉県 熊谷 岐阜県 多治見 山形県 山形 山梨県 甲府 和歌山県 かつらぎ 静岡県 天竜 山梨県 勝沼 埼玉県 越谷 群馬県 館林 群馬県 上里見 愛知県 愛西 千葉県 牛久 静岡県 佐久間 愛媛県 宇和島 山形県 酒田 岐阜県 美濃 群馬県 前橋 千葉県 茂原 埼玉県 鳩山 大阪府 豊中 山梨県 大月 山形県 鶴岡 愛知県 名古屋
入出力を標準入力から取ってくるところ、filepathを取ってくるところは本質ではないので、やめました。
練習としてはQ12でできたので。
またrune
で処理するところもReadLine()
などにしてわかりやすくしました。
14. 先頭からN行を出力
自然数Nをコマンドライン引数などの手段で受け取り,入力のうち先頭のN行だけを表示せよ.確認にはheadコマンドを用いよ.
gist25538f623bc1425da5da9507b34823a2
# head -n 10 ../data/hightemp.txt 高知県 江川崎 41 2013-08-12 埼玉県 熊谷 40.9 2007-08-16 岐阜県 多治見 40.9 2007-08-16 山形県 山形 40.8 1933-07-25 山梨県 甲府 40.7 2013-08-10 和歌山県 かつらぎ 40.6 1994-08-08 静岡県 天竜 40.6 1994-08-04 山梨県 勝沼 40.5 2013-08-10 埼玉県 越谷 40.4 2007-08-16 群馬県 館林 40.3 2007-08-16
読み込んだ行数をカウントして、標準入力で受け取った整数になるまでループ回すだけです。
15. 末尾のN行を出力
自然数Nをコマンドライン引数などの手段で受け取り,入力のうち末尾のN行だけを表示せよ.確認にはtailコマンドを用いよ.
gistc953b981cec15f23ef604cf03f473e38
# tail -n 10 ../data/hightemp.txt 愛媛県 宇和島 40.2 1927-07-22 山形県 酒田 40.1 1978-08-03 岐阜県 美濃 40 2007-08-16 群馬県 前橋 40 2001-07-24 千葉県 茂原 39.9 2013-08-11 埼玉県 鳩山 39.9 1997-07-05 大阪府 豊中 39.9 1994-08-08 山梨県 大月 39.9 1990-07-19 山形県 鶴岡 39.9 1978-08-03 愛知県 名古屋 39.9 1942-08-02
ファイルサイズだけを取得できるのであれば、逆から一文字ずつ読む実装のほうが巨大なファイルを読み込む場合にすぐ表示できてよさそうです。
今回は全部の行を読み込み、出力用output
に溜め込み、最後に標準出力させました。
mod
演算させておき、output = append(output[i:], output[:i]...)
することで順番通りに出力できるのがポイントです。
16. ファイルをN分割する
自然数Nをコマンドライン引数などの手段で受け取り,入力のファイルを行単位でN分割せよ.同様の処理をsplitコマンドで実現せよ.
gist82a113dbf0bcf2436fe80a44532c589d
# split -l 13 ../data/hightemp.txt # cat xaa 高知県 江川崎 41 2013-08-12 埼玉県 熊谷 40.9 2007-08-16 岐阜県 多治見 40.9 2007-08-16 山形県 山形 40.8 1933-07-25 山梨県 甲府 40.7 2013-08-10 和歌山県 かつらぎ 40.6 1994-08-08 静岡県 天竜 40.6 1994-08-04 山梨県 勝沼 40.5 2013-08-10 埼玉県 越谷 40.4 2007-08-16 群馬県 館林 40.3 2007-08-16 群馬県 上里見 40.3 1998-07-04 愛知県 愛西 40.3 1994-08-05 千葉県 牛久 40.2 2004-07-20 # cat xab 静岡県 佐久間 40.2 2001-07-24 愛媛県 宇和島 40.2 1927-07-22 山形県 酒田 40.1 1978-08-03 岐阜県 美濃 40 2007-08-16 群馬県 前橋 40 2001-07-24 千葉県 茂原 39.9 2013-08-11 埼玉県 鳩山 39.9 1997-07-05 大阪府 豊中 39.9 1994-08-08 山梨県 大月 39.9 1990-07-19 山形県 鶴岡 39.9 1978-08-03 愛知県 名古屋 39.9 1942-08-02
Q10を再利用しました。
書き込み用ファイルのポインタwfp
を使いまわしたかったですが、if
文の中で再定義しようとするとスコープから外れてしまってつらい感じでした。
N個のファイルを作成するものと勘違いしてやり直しがあったので時間が掛かりました。そのボツの供養
17. 1列目の文字列の異なり
1列目の文字列の種類(異なる文字列の集合)を求めよ.確認にはsort, uniqコマンドを用いよ.
gistd7efd041ef928797af814d56bcef28ce
# cut -f 1 ../data/hightemp.txt | sort | uniq 千葉県 和歌山県 埼玉県 大阪府 山形県 山梨県 岐阜県 愛媛県 愛知県 群馬県 静岡県 高知県
必ずしもソートする必要はありませんが、sortパッケージのinterface
を実装するのをやってみたかったので自作型runeSlice
のsort
を実装してみました。
18. 各行を3コラム目の数値の降順にソート
各行を3コラム目の数値の逆順で整列せよ(注意: 各行の内容は変更せずに並び替えよ).確認にはsortコマンドを用いよ(この問題はコマンドで実行した時の結果と合わなくてもよい).
gist89c20ddb3587c1407c5b1099ff7b1bad
# sort -nk3 ../data/hightemp.txt 千葉県 茂原 39.9 2013-08-11 埼玉県 鳩山 39.9 1997-07-05 大阪府 豊中 39.9 1994-08-08 山形県 鶴岡 39.9 1978-08-03 山梨県 大月 39.9 1990-07-19 愛知県 名古屋 39.9 1942-08-02 岐阜県 美濃 40 2007-08-16 群馬県 前橋 40 2001-07-24 山形県 酒田 40.1 1978-08-03 千葉県 牛久 40.2 2004-07-20 愛媛県 宇和島 40.2 1927-07-22 静岡県 佐久間 40.2 2001-07-24 愛知県 愛西 40.3 1994-08-05 群馬県 上里見 40.3 1998-07-04 群馬県 館林 40.3 2007-08-16 埼玉県 越谷 40.4 2007-08-16 山梨県 勝沼 40.5 2013-08-10 和歌山県 かつらぎ 40.6 1994-08-08 静岡県 天竜 40.6 1994-08-04 山梨県 甲府 40.7 2013-08-10 山形県 山形 40.8 1933-07-25 埼玉県 熊谷 40.9 2007-08-16 岐阜県 多治見 40.9 2007-08-16 高知県 江川崎 41 2013-08-12
3コラム目と指定されているので直書きでも良い気がしましたが、各コラムでソートできるようにしたかったので、Jxckさんの記事を参考にソート条件を可変にしました。
Go1.8ではsort.Slice
が実装されるのでByXXX
を書かなくて良くなりそうです。
(ベンチマークを見る限り、速度は犠牲になっているようなので要件に合わせてチューニングが必要そうですが)
19. 各行の1コラム目の文字列の出現頻度を求め,出現頻度の高い順に並べる
各行の1列目の文字列の出現頻度を求め,その高い順に並べて表示せよ.確認にはcut, uniq, sortコマンドを用いよ.
gist4ea5282a6a739f8f3c7e8e0fc954fc91
# cut -f 1 ../data/hightemp.txt | sort | uniq -c | sort -r 3 群馬県 3 山梨県 3 山形県 3 埼玉県 2 静岡県 2 愛知県 2 岐阜県 2 千葉県 1 高知県 1 愛媛県 1 大阪府 1 和歌山県
ファイル内容を読み込んでから構造体に格納したものの、各フィールドを独自型にした結果、コードがひたすら長くなってしまったので微妙な気がします。メンテナンス性も低いのでベストプラクティス的なもの知る必要ありです。。。。
A Tour of GoのInterface valuesあたりを早く読めばよかった
感想
準備運動から久しく時間が空きましたが、第2章でした。
Go言語の筋トレのつもりでしたが、Linuxコマンドも知らないものが多く、勉強になりました。
今回のコードはGithubにも置いてあります。