TextCounterの中身に関して
やっほー。前回のエントリで渡されたテキストファイルの行数・文字数・単語数・各アルファベットの出現回数を返すプログラムを作ったと書きました。
その中身ですが、基本的にjava.io.*のインポートによりライブラリにあるクラスをフル活用する感じです。
行数はreadLine()をwhile(line != null)内でゴリゴリ回します。whileの終了条件line = nullを判定するためにwhile内で次の行を読み込み更新します。
これで行数のカウントは終わり。
次に文字数ですが、これもいまの考え方をそのまま使えます。
各行の長さを.length()で取得し合計したものが文字数になります。したがって、前半の2つのメソッドはほとんど同じです。
次に各アルファベットの出現回数に関してです。大文字と小文字の区別は取得した文字をtoUpperCaseに放り込んでからfor(int i = 60; i <= 90; i++)のループで一文字ずつ判定していけばよいです。i = 60はAのASCⅡ上のコードを表します。
詳しくはこちらを。
行を読み込むreadLine()や文字を読み込むread()はintを要求するので、(char c == 'A'; c <= 'Z'; c++)は使えないのです。
詳しくはこちら。
InputStream (Java Platform SE 6)
問題は単語数です。スペースでsplitする方法ではうまくいかないことがあったので、別の方法を考えました。うまくいきませんでしたが…
スペースでsplitする方法以外で考えたのは、スペースを区切り文字としダブるスペースの場合にはカウントしない方法で、連続したスペースをカウントの際に排除できる(はずの)ものでした。こんな感じのものです。実際のコードは持ち出せないので記憶を基に再現しました。まずは前半。こちらに件の処理が含まれています。スクショ内で説明を完結させようとコメントをぶち込みまくりましたが、これはお行儀が悪いのでやめましょう。
何をしているのかを順に説明します。
17行目でこのメソッドの戻り値を定義し初期化しています。
23行目と24行目ではread()を用いてテキストファイル内の文字を先頭から一文字ずつ読み込む準備をしています。問題はここからです。二つの真偽値isNotSpace_1, isNotSpace_2は各文字に対して文字であればtrueに、スペース又は改行記号であればfalseになります。そして、isNotSpace_1はi+1番目の文字、isNotSpace_2はi番目の文字の状態true/falseに対応しています。具体例をあげると、
apple[ ]banana[ ]chocolate[\n]
delicious[ ][ ]east[ ]fruits[\n] ([ ]はスペースを、[\n]は改行記号を明示的に表現)
というテキストがあるとします。先頭からread()を使って読み込むと、最初は、appleのaとなります。この時、isNotSpace_1 = trueとします。そうすると、真偽値は、isNotSpace_2 = false, isNotSpace_1 = trueとなります。次の文字を同じように読み込むと、apppleのpなので、isNotSpace_1から値を受け取ってisNotSpace_2 = trueに、isNotSpace_1 = trueとなります。これを繰り返すとappleのeを読み込んだ時にisNotSpace_1 = true, isNotSpace_2 = trueになります。次の文字は[ ]なのでisNotSpace_1 = falseとなります。コードでは36行目のelse節に入り、if節によりwordNumberCountでカウントされます(というかされるはずだった)。とまあ、こんな感じで処理を繰り返していきます。
正直、40行目の条件が正しいと思えない。内容的にも位置的にも。
そして後半。
実際に動かしてみるとelse節に入るものの明らかに大きい値を返されてしまい、途方に暮れてしまいました。
実際の単語数のカウントってどういうアルゴリズムで動いているのか…