手軽にアプリが作れるってところがいいですね。Java はあまり使ってなかったのですが、勉強しててよかったです。ほんとそう思います。
今は、とりあえず、Aquestalk2 で漢字を含んだ文章を読ませる実験をしています。辞書はSDカードに直接書き込んでいるので、これが自動化できたら誰でも使えるようになるので、そうなったら公開できると思います。
今回は GoSen を Android 向けに改造したものを使って日本語を解析しています。MeCab を元に Java で書き直した Sen。その Sen を補強した GoSen です。それを Android で動くように少し書き換えました。Android で GoSen を動かそうとしたら、どういうわけか XML で書かれた設定ファイルを読み込むところで止まってしまいました。そこでXML関連の部分を書き直してみました。別なシンプルな方法があったかもしれませんが、とりあえずこれでいいはずです。
具体的には下記のように、Configuration loadConfiguration(String configurationFilename) を次の二つのメソッドで置き換えました。そしてそれに伴い必要なimport文を追加しました。
/**
* get a XML Text field
*
* @param XmlPullParser
* @param The Tag name String
* @return The Text String
*/
private static String getXMLText(XmlPullParser parser,String name) {
try {
if ( parser.next() == XmlPullParser.TEXT) {
String text = parser.getText();
if ( parser.next() == XmlPullParser.END_TAG && name.equals(parser.getName()) ) {
return text;
}
}
}catch(Exception e) {
}
throw new IllegalArgumentException( "element '" + name + "' is invalid");
}
/**
* Loads a tokenizer configuration file for Android
*
* @param configurationFilename The filename of the configuration to load
* @return The loaded configuration
*/
private static Configuration loadConfiguration(String configurationFilename) {
String dictionaryVersion = "";
Configuration configuration = new Configuration();
try {
File configurationFile = new File(configurationFilename);
String parentDirectory = configurationFile.getParent();
if (parentDirectory == null) {
parentDirectory = ".";
}
String separator = System.getProperty("file.separator");
configuration.connectionCostFilename = parentDirectory + separator + CONNECTION_COST_DATA_FILENAME;
configuration.partOfSpeechDataFilename = parentDirectory + separator + PART_OF_SPEECH_DATA_FILENAME;
configuration.tokenFilename = parentDirectory + separator + TOKEN_DATA_FILENAME;
configuration.trieFilename = parentDirectory + separator + TRIE_DATA_FILENAME;
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setInput(new FileInputStream(configurationFilename),"UTF-8");
int eventType;
while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT){
if (eventType == XmlPullParser.START_TAG && parser.getDepth() == 1 ) {
if ( "configuration".equals(parser.getName()) ) {
while (true) {
eventType = parser.next();
if ( eventType == XmlPullParser.END_TAG ) {
if ( "configuration".equals(parser.getName() )) {
break;
} else {
throw new IllegalArgumentException( "invalid end tag");
}
}
if ( eventType == XmlPullParser.TEXT ) {
continue;
}
if ( eventType != XmlPullParser.START_TAG ) {
throw new IllegalArgumentException( "invalid event");
}
String name = parser.getName();
if (name.equals("dictionary-version")) {
dictionaryVersion = getXMLText(parser,name);
} else if (name.equals("tokenizer")) {
configuration.tokenizerClassName = getXMLText(parser,name);
} else if (name.equals("unknown-pos")) {
configuration.unknownPartOfSpeechDescription = getXMLText(parser,name);
} else {
throw new IllegalArgumentException( "unknown tag");
}
}
}
}
}
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
if (!dictionaryVersion.equals("1.0")) {
throw new IllegalArgumentException("Invalid dictionary version \"" + dictionaryVersion + "\"");
}
return configuration;
}
JARファイル
gosen-android-1.01.jar
このファイルのライセンスは LGPL です。
2011.01.06 更新
2.6.2以降のipadicにも対応させました。
関連ページ:
・日本語形態素解析システムのJava実装SenをAndroid上で動かす
・Sen Project
・GoSen
GoSen を使うときに気をつけることは GoSen は LGPLライセンスだということです。GPL/LGPLライセンスのソフトは利用する分にはありがたいのですが、その反面、ソフトを書く側になると使いにくいのも事実です。ちゃんと理解しているか自信はありませんが、今回は LGPL のファイルからなる jar ファイルを利用するので、それを利用する側の本体のプログラムのソースを公開する義務は生じないと思います。間違っていたら指摘ください。
余計なことで悩まないように、誰かが現時点のトリプルライセンスになっている MeCab を元に、新しく Java で書き直して同じトリプルライセンスで公開してくれるとありがたいですね。そのときは是非 Man という名前で。
MeCab そのものを Android で使うというのもありだと思って、MeCab を JNI で動かせないかと模索もしています。既に ARM 向けにクロスコンパイルができることは確認できました。あとは、NDK の使い方を覚えたら何とかなるかもしれません。当然、それがうまくいけば次の段階として、内部で MeCab を使っている Open JTalk を Android でも使えるようにしたいと思っています。
最終的な目標は、Andorid で動く日本語のスクリーンリーダーです。Linux では Gnome Orca の続きをやらないといけないのに、NVDA もお手伝いしたいって気持ちはあるんですが、ちょっと今は、しばらくアンドロイドでいろいろプログラムを作ってみようと思います。