第2章の10から11まで(言語処理100本ノック2020)

Posted by johtani on Friday, May 8, 2020

目次

気づいたら1ヶ月サボってました、ごめんなさい。。。

Rustで言語処理100本ノックの第2章をはじめました。

前回はこちら

確認用のUnixコマンド

確認用のファイルを先に生成して置きました。 これで、Rustでコードを書いて、作成済みの確認ファイルを元にassert_eq!でチェックするという方式を取ろうかと。

で、コマンド群はこちらです。

Unix/Linuxコマンド、昔から使っています。が、なにかちょっとした文字列処理やファイル処理をやるときは、Javaのプログラム(最近だとPython)を書くというのが基本になってるので、結構、使ったことの無いコマンドが今回ありました。使ったことがなかったのはこちらです。

  • sed
  • tr
  • expand
  • paste
  • cut
  • split

sedとかは普通さわってるだろ?って思われそうですね。。。

で、コマンドをmanで調べつつやりました、macOS上で。 これがまたいくつか罠があったので書き残しておきます(自分が知らないだけかもしれないので、おかしいところがあったらツッコミお願いします。)。

sedコマンドでのタブの扱い

## sed command for macOS. If using Linux, use "\t" for tab character
cat $INPUT_FILE_NAME | sed -e 's/	/ /g' > $OUTPUT_DIR/11_sed.txt

\tで行けると思ったのですが、うまく動きませんでした。<tab>みたいな書き方もあると思うのですが、これも駄目で、結局タブ文字をそのまま打ち込みました。。。 これ、めんどくさくないですか??? ちなみに、ターミナルで動作確認して、GitHubにあげてあるシェルファイルにコピペしてたのですが、CLionに貼り付けたらタブ文字がスペースに変換されてしまってて20分くらい悩みました。。。

splitコマンドに-nオプションがない


LINES=`cat $OUTPUT_DIR/10.txt`
SPLIT_LINES=`echo $LINES/$N | bc`
split -a 1 -l $SPLIT_LINES $INPUT_FILE_NAME $OUTPUT_DIR/16_

splitコマンドについてググると、-nで指定した数のファイルに分割できるという記事がいくつも出てくるのですが、man splitをターミナル上でやるとそんなオプションがないと。。。 macOSがBSD系だからっぽいです。 ということで、行数を元に、指定した数(N)で行数を割ってから、指定行数ごとにファイルを分割する方式にしました。

これらのコマンドの違いはHomebrewとかでインストールするとなくなるのかなぁ?(めんどくさいので確認してないですが。。。)

ってことで、2章のそれぞれの課題の正解ファイルの生成はこれでできたはずです。

10. 行数のカウント

wc -lですね。

// ch02-10 行数のカウント
pub fn word_count(file_name: &str) -> usize {
    let f = File::open(file_name).expect("file not found");
    let buf = BufReader::new(f);
    return buf.lines().count();
}

ファイルを読み込んで行数を数えます。 文字列として読み込んで改行コードの数を数えるというのもありかな?と思いましたが、RustのBufReaderlines()という行のイテレータ?が取れることがわかったので、それでカウントを取りました。

11. タブをスペースに置換

// ch02-11 タブをスペースに置換
pub fn tab_2_space(file_name: &str) -> String {
    let mut f = File::open(file_name).expect("file not found");
    let mut contents= String::new();
    f.read_to_string(&mut contents).expect("read error");
    return contents.replace("\t", " ");
}

こっちはファイル全体を文字列に読み込んでしまってから、文字列のreplaceで置換するという方式です。 ファイルが大きい場合にこれでいいのか?という問題がある気がしますが、まずはこの実装にしました。 やるとしたら、readメソッドとbufferを用意して、少しずつ読みながら、置換して吐き出す感じでしょうか? ちゃんとした文字コードの区切りで取れるかどうかを気にしないと行けないと思うので、思ったよりはめんどくさくなりそう。

BufReaderをつかってread_lineのほうがましかも?

まとめ

ということで、サボっていたのを再開しました。 Rustのコードを書く前に、Unixコマンドの処理に結構悩みましたw

Rustのコードとしてはファイル処理なので、今後も役立つ気がしてます。 ということで、頑張っていくぞと。


comments powered by Disqus