id:d-kamiさんから改良版Make2Gram付きトラックバックを頂きました(連絡方法がわからんのでトラックバックで – マイペースなプログラミング日記)(はてなダイヤリーから移転前)。d-kamiさん、ありがとうございます。
上記のページにあるコードから、TreeMapやsubstringを用いたbigramの切り出し・カウント方法などを学ばせて頂きました。
さて、今回の実装その2は以下の機能を加えました。
- コマンドライン引数にディレクトリ名を指定して、そのディレクトリ以下のファイル全てを処理の対象とする。
- N-gram情報には文書IDと部分文字列の出現位置を格納するようにデータ構造の拡張。
そして今回、指定ディレクトリ以下のファイルを再帰的に読み込んでいく処理はJava 再帰的にファイルを検索 / Chat&Messengerを参考にさせて頂きました。
Make2Gram.java
import java.io.File; ファイル読み込み部分とbigram切り出し部分のループを二つに分けたのは今後の拡張の為です。 import java.util.ArrayList; おー、なんか楽しくなってきました。
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.TreeMap;
public class Make2Gram{
public static void main(String[] args) throws IOException{
if(args.length == 0){
System.out.println(“引数にディレクトリ名を指定してください”);
System.exit(1);
}
int N = 2; // bigram
// http://sattontanabe.blog86.fc2.com/blog-entry-55.html
// Java 再帰的にファイルを検索 / Chat&Messenger
// のクラスFileSearchを使用しています
FileSearch search = new FileSearch();
File[] files = search.listFiles(args[0], null); // 全てのファイルを取得
// ファイルIDとパスの対応表
TreeMap
ArrayList
for(int i=0; i < files.length; i++){
fileMap.put(i, files[i].getAbsoluteFile());
BufferedReader br = new BufferedReader(new FileReader(files[i]));
StringBuilder sb = new StringBuilder();
String line;
while((line = br.readLine()) != null)
sb.append(line);
br.close(); // ファイル内容(RAW)を格納
String text = sb.toString(); // ファイルの内容 改行抜き
docs.add(text);
}
//テキストの部分文字列とそのIndexRecordクラスを関連付けるMap
//TreeMapなのでMapのキーにした部分文字列でソートされる
TreeMap
for(int i = 0; i < fileMap.size(); i++){
// ファイルごとの処理
String text = docs.get(i);
for(int j = 0; j < text.length() - N; j++){
//テキストからN文字取り出す
String gram = text.substring(j, j + N);
if(gramMap.containsKey(gram)){
//gramMapに登録されてる文字列ならカウントを増やす
IndexRecord ir = gramMap.get(gram);
ir.count++;
ir.file_id.add(i);
ir.word_pos.add(j);
gramMap.put(gram, ir);
}else{
//gramMapに登録されていない文字列なら登録
gramMap.put(gram, new IndexRecord(i, j));
}
}
}
for(String part : gramMap.keySet()){
System.out.printf("%s : %sn", part, gramMap.get(part));
}
}
}
[/java]
IndexRecord.java(N-gram情報を格納するクラス)
public class IndexRecord {
// 出現回数
Integer count;
// 出現したファイルID
ArrayList
// ファイル内の出現位置(文書の先頭からのオフセット)
ArrayList
public IndexRecord(int id, int pos) {
count = 1;
file_id = new ArrayList
file_id.add(id);
word_pos = new ArrayList
word_pos.add(pos);
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(count);
for(int i = 0; i < file_id.size(); i++){
sb.append(" (" + file_id.get(i) + ", " + word_pos.get(i) + ")");
}
return sb.toString();
}
}
[/java]
実行結果の一部
・・・<中略>・・・
定の : 2 (0, 40) (1, 59)
対象 : 1 (0, 28)
度」 : 1 (2, 71)
度を : 1 (0, 58)
数の : 1 (1, 46)
文字 : 3 (0, 2) (0, 43) (1, 61)
文書 : 3 (1, 48) (2, 5) (2, 22)
文検 : 1 (1, 1)
新順 : 1 (2, 10)
方法 : 1 (0, 63)
更新 : 1 (2, 9)
書の : 1 (2, 23)
書は : 1 (2, 6)
書( : 1 (1, 49)
検索 : 5 (0, 26) (1, 2) (1, 65) (2, 0) (2, 45)
求め : 1 (0, 60)
法」 : 2 (0, 10) (0, 17)
・・・<中略>・・・
今後の改良点