package jp.ac.waseda.info.kake.moca;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import jp.ac.waseda.info.kake.moca.dict.MocaDictionaries;
import jp.ac.waseda.info.kake.moca.viterbi.MocaViterbi;
import org.atilika.kuromoji.Token;
import org.atilika.kuromoji.Tokenizer;
import org.atilika.kuromoji.dict.UserDictionary;
import jp.ac.waseda.info.kake.system.PrintIntegerMaker;
public class MocaTokenizer extends Tokenizer {
public static final boolean split = true;
// TODO splitはtrueでいい? trueにしてると、崩れた表記解析で邪魔になることはない? 例: あ、は、は、は、、、。
public static final boolean unknownFixMode = true;
public static final boolean convertsSize = true;
public static final Mode kuroMode = Mode.NORMAL; // TODO サーチモードは使わなくていい?
/**
* MoCAの挙動を示します。
*
* @author Tony
*/
public enum MocaMode {
/**
* くだけた表現解析を行わず、基本的にKuromojiと同様の結果を返します。
*/
ESPRESSO(false, false),
/**
* くだけた表現解析を行います。返される形態素の表層表現は、辞書上の表記に訂正されます。
*/
LATTE(true, false),
/**
* くだけた表現解析を行います。返される形態素の表層表現は、元の文の表層表現のままです。
*/
MOCHA(true, true),
/**
* 長音節最適化機能のみを有効化します。
*/
SYLLABLES(true, false, true),
/**
* 読み仮名検索機能のみを有効化します。
*/
READING(false, true, true);
/**
* 何らかの崩れた表記解析を行うか否か。
*
* 必ず analysesSyllables || analysesReading と同値になります。
*/
public final boolean analysesColloquial;
/**
* 長音節最適化を行うか否か
*/
public final boolean analysesSyllables;
/**
* 読み仮名検索を行うか否か
*/
public final boolean analysesReading;
/**
* trueの場合、形態素解析結果を、崩れた表記のまま(元の文の表記のまま)返します。
*
* falseの場合、形態素解析結果を、辞書上の表記に直して返します。
*/
public final boolean returnsColloquial;
private MocaMode(boolean analyses, boolean returns) {
this(analyses, analyses, returns);
}
private MocaMode(boolean analysesSyllables, boolean analysesReading, boolean returns) {
this.analysesSyllables = analysesSyllables;
this.analysesReading = analysesReading;
this.analysesColloquial = analysesSyllables || analysesReading;
returnsColloquial = (analysesSyllables || analysesReading) && returns;
}
/**
* 与えられた文字列に対応するMocaModeを返します。valueOfよりも柔軟性があります(大文字/小文字非依存、MOCHA / MOCA
* のどちらの表記も可)。基本的に、valueOfではなくこちらを用いることを推奨します。
*
* @param value
* @return
* @throws IllegalArgumentException
*/
public static MocaMode getMocaMode(String value) throws IllegalArgumentException {
value = value.toUpperCase();
try {
return valueOf(value);
} catch (IllegalArgumentException e) {
if (value.equals("MOCA"))
return MOCHA;
throw e;
}
}
}
public MocaTokenizer() throws IOException {
this(MocaMode.MOCHA);
}
public MocaTokenizer(String userDictionaryPath) throws IOException {
this(userDictionaryPath, MocaMode.MOCHA);
}
public MocaTokenizer(UserDictionary userDictionary) {
this(userDictionary, MocaMode.MOCHA);
}
public MocaTokenizer(MocaMode mode) {
this((UserDictionary) null, mode);
}
public MocaTokenizer(String userDictionaryPath, MocaMode mode) throws IOException {
this(UserDictionary.read(new BufferedInputStream(new FileInputStream(userDictionaryPath))), mode);
}
public MocaTokenizer(UserDictionary userDictionary, MocaMode mode) {
super(getMocaViterbi(userDictionary, mode), MocaDictionaries.getDictionary(), MocaDictionaries.getUnknownDictionary(),
userDictionary, kuroMode, split, unknownFixMode);
}
private static MocaViterbi getMocaViterbi(UserDictionary userDictionary, MocaMode mode) {
return new MocaViterbi(MocaDictionaries.getTrie(), MocaDictionaries.getDictionary(),
MocaDictionaries.getUnknownDictionary(), MocaDictionaries.getCosts(), userDictionary, mode);
}
/**
* MoCAモードの切り替えを行います。
*
* @param mode
*/
public void setMocaMode(MocaMode mode) {
if(viterbi instanceof MocaViterbi)
((MocaViterbi) viterbi).setMocaMode(mode);
}
/**
* デモ用。形態素解析結果を出力します。
*
* @param line
*/
public void printTokens(String line) {
List<Token> tokens = tokenize(line);
PrintIntegerMaker pim = new PrintIntegerMaker(tokens.get(tokens.size() - 1).getPosition());
for (Token token : tokens) {
System.out.println(pim.getPrintInteger(token.getPosition()) + ": " + token.getSurfaceForm() + "\t"
+ token.getAllFeatures());
}
}
}