//-------------------------------------------------------------------- // 完全一致の辞書検索 (再起にすると時間がかかりすぎるので再起なし) // static public WordChain DividedWordSearch(string str) { WordTable wt; WordChain wc; #if DEBUG_LOG KJ_Analyzer.WriteDebugLog("DividedWordSearch:" + str); #endif SearchResult sResult = KJ_dict.SearchFull(str); if (sResult == null) { // strが辞書にない // wc = WordPartProc(wt); return(null); } wt = new WordTable(str); wc = new WordChain(); // 検索できた wt.SetResult(sResult); // wt3に検索結果を入れる //wt.IsDevided=true; // 分割語であるマーク wc.Add(wt); return(wc); }
//------------------------------------------------------- // 分割なし完全一致の語 static public WordTable Scan(WordChain wChain, WordTable wTable) { if (wTable.IsTranslated()) { return(wTable); // 変換済みなら何もしない } // 翻訳しなくていい文字は抜ける if (!wTable.IsWord() || // 空白や制御文字 wTable.IsDigit() || wTable.IsOther()) // 記号 { return(wTable); } // 助詞なら抜ける if (wTable.posCategory == PosCategory.PP) { return(wTable); } // 独立した1文字の語は辞書より先に検索 (単独の이など) if (wTable.word.Length == 1) { CheckOneWord(wTable); if (wTable.transWord != "") { return(wTable); // match } } // 全体で完全一致で検索 SearchResult sResult = KJ_dict.SearchFull(wTable.word); if (sResult != null) { wTable.SetResult(sResult); return(wTable); // 完全一致で見つかった } // 4文字語の調査 (部分分割後は使わない) WordChain wc = Check4Chars(wTable); if (wc != null) { wChain.Swap(wTable, wc); return(wc.Tail); } return(wTable); }
// (*2) xxxxする、xxxxさせる etc // //====================================================================== // // private methods // //------------------------------------------------------------- // 品詞条件付きサーチ static private string SearchDictwithPos(string inputword, string pos) { SearchResult sResult = KJ_dict.SearchFull(inputword); if (sResult == null) { return(""); } return(sResult.MakeTranslatedText(pos)); }
//------------------------------------------------------------------ // 3文字語の調査 (部分分割後も使う) static private WordChain Check3Chars(WordTable wTable) { SearchResult sResult; // ABC ---> AB + C String head = wTable.word.Remove(2, 1); String suffix = wTable.word.Substring(2, 1); sResult = KJ_dict.SearchFull(head); if (sResult != null) { // lastWordListにあるか調べる string translatedSuffix = KJ_Filter.SearchSuffix(suffix); if (translatedSuffix != "") { WordTable headWt = new WordTable(head); headWt.SetResult(sResult); WordChain wc = new WordChain(headWt); WordTable wt = new WordTable(suffix, translatedSuffix); wt.Cost = 5; wc.Add(wt); return(wc); } } // ABC ---> A + BC String prefix = wTable.word.Remove(1, 2); String tail = wTable.word.Substring(1, 2); sResult = KJ_dict.SearchFull(tail); if (sResult != null) { // lastWordListにあるか調べる string translatedPrefix = KJ_Filter.SearchPrefix(prefix); if (translatedPrefix != "") { WordTable wt = new WordTable(prefix, translatedPrefix); wt.Cost = 5; WordChain wc = new WordChain(wt); WordTable tailWt = new WordTable(tail); tailWt.SetResult(sResult); // 全体でmatch wc.Add(tailWt); return(wc); } } return(null); }
//------------------------------------------------------------------ // 4文字語の調査 (部分分割後は使わない) static private WordChain Check4Chars(WordTable wTable) { SearchResult sResult; if (KJ_dict.inputIsHangul) { // 4文字以外は抜ける。 if (wTable.word.Length != 4) { return(null); } if (wTable.word.EndsWith("하게")) { string head = wTable.word.Remove(2, 2); // 4文字なので固定 sResult = KJ_dict.SearchFull(head); if (sResult != null) { WordTable tempwt = new WordTable(head); tempwt.SetResult(sResult); string trans = tempwt.GetTranslatedText(); wTable.transWord = trans + "に"; wTable.Cost = 10; wTable.posCategory = PosCategory.PP; WordChain wc = new WordChain(wTable); // これだけならwtでもいいが、汎用化のためwcで返す return(wc); } } } return(null); }
//-------------------------------------------------------------- // startwtで始まる熟語を最長一致でチェックする // // (before) // -----wt1-----wt2-----wt3-----wt4-----wt5-----wt6----- // ↑ ↑ // startwt matched // // (after) // -----wt1-----idiomwt-----wt5-----wt6----- // // チェーン中の熟語を成すテーブルは1つにまとめる。 // (正確には熟語のテーブルを挿入し、個々の語のテーブルは削除) // static public WordTable Search(WordChain wc, WordTable startwt) { //熟語は語単位より優先 // if(startwt.IsTranslated()){ // return null; // 翻訳済みの語は触らない // } bool isExist; // 辞書中にチェック対象の語(熟語)が存在するか? WordTable idiomwt = null; // 熟語テーブル SearchResult sResult; string word = startwt.word; // startwtが翻訳済みで助詞なら何もしない // 暫定的 2005.08.26 // if(startwt.IsTranslated() && startwt.pos == PosCategory.PP ){ // return(null); // not found // } // 前方一致で該当なしなら // この語で始まる熟語は辞書にない isExist = KJ_dict.CheckForward(word); if (!isExist) { return(null); // not found } // 前方一致でmatchしたので先読みして熟語チェック String word2 = ""; string next = ""; WordTable nextTable = startwt.next; WordTable matched = startwt; // 次の語以降を足しながらチェック while (nextTable != null) { if (nextTable == null || nextTable.word == "") { break; // 次の語なしなら抜ける } next = nextTable.word; char ch = next[0]; if (Char.IsSeparator(ch)) { next = " "; } if (next == " ") { word = word + next; nextTable = nextTable.next; // 次の語へ continue; // 空白付加だけでは再検索しない } word2 = word + next; //次の語を足して前方一致チェック isExist = KJ_dict.CheckForward(word2); if (!isExist) { // nextを足したら,一致しない。→ これ以上先を見る必要なし break; } // 一致した部分まででで完全一致検索 sResult = KJ_dict.SearchFull(word2); if (sResult != null) { // string trimword = word2; // trimword = trimword.Replace(" ", ""); // 空白削除 if (IsValidIdiom(sResult)) // 長さ4以上でないと採用しない // 熟語が見つかった { idiomwt = new WordTable(word2); idiomwt.charCategory = startwt.charCategory; // 先頭文字種で (混ざっている可能性あるが) idiomwt.posCategory = PosCategory.Idiom; idiomwt.SetResult(sResult); matched = nextTable; // 完全一致した最後のテーブル } } // さらに次の語へ word = word2; // nextを足したものを元とする。 nextTable = nextTable.next; // 次の語へ } // while loop if (startwt.word == word) { // 熟語でなく単なる入力語の完全一致の時は返さない return(null); } if (idiomwt != null) { // 熟語が見つかっている wc.Insert(matched, idiomwt); // startwtからmatchedまでは消していい。 WordTable delwt = startwt; while (true) { wc.Delete(delwt); if (delwt == matched) { break; } delwt = delwt.next; } // 熟語のテーブルを返す return(idiomwt); } // 熟語なし return(null); }
//-------------------------------------------------------------------- // 語の変換 (語の分解あり) // 語分解で翻訳済み末尾がずれることがあるのでWordTableを返す // ABCDEF という語に対し、 // ABCDE + F // ABCD + EF // ABC + DEF // : : // と調べていき、最小コストの訳語がとれる分割を採用する // static public WordChain WordPartProc(WordTable wt) { SearchResult sResult; String str = wt.word; if (wt == null) { return(null); } if (wt.word != null && wt.word.Length == 1) // 1文字検索はしない { return(null); } if (wt.IsTranslated() || wt.IsDigit()) { return(null); // 翻訳済みまたは 数字なら 何もしない } #if DEBUG_LOG KJ_Analyzer.WriteDebugLog("WordPartProc:" + wt.word); #endif // 再起に備え,まず完全一致で検索 sResult = KJ_dict.SearchFull(str); if (sResult != null) { wt.SetResult(sResult); // 全体でmatch WordChain wc = new WordChain(wt); return(wc); } // 部分語の2文字は分割しない if (wt.word != null && wt.word.Length == 2 && wt.divided != Divided.Non) { return(null); } // 3文字の「ハングルまたは漢字」なら特別チェック if (wt.word != null && wt.word.Length == 3 && wt.divided != Divided.Non && // 部分語の3文字語は除外 (CodeCheck.IsHangul(wt.word) || CodeCheck.IsKanji(wt.word)) ) { WordChain wc3 = Check3Chars(wt); if (wc3 != null) { return(wc3); } } // int target_len=2; // 2005.09.03 やっぱり1文字まで切らないとだめだ int target_len = 1; int str_len = str.Length; int minimumCost = 9999; WordChain minimumCostChain = null; // 前から1文字ずつ落としつつ,検索。 while (true) { int start = str_len - target_len; // if( start <= 1 ){ // 2005.09.03 if (start <= 0) { break; } // 文字列を分割する // str --> str2 + str3 // String str2 = str.Remove (start, target_len ); // String str3 = str.Substring(start, target_len ); // 前から分割に変えた(2005.08) String str2 = str.Remove(target_len, start); String str3 = str.Substring(target_len, start); //あとできれいに // 前と後ろを、それぞれ検索 WordChain wc2 = DividedWordSearch(str2); WordChain wc3 = DividedWordSearch(str3); #if DEBUG_LOG KJ_Analyzer.WriteDebugLog("str2/str3:" + str2 + "/" + str3); #endif WordTable wt2, wt3; if (wc2 == null) { wt2 = new WordTable(str2); wc2 = new WordChain(wt2); } if (wc3 == null) { wt3 = new WordTable(str3); wc3 = new WordChain(wt3); } // 分割情報設定 if (wt.divided == Divided.Non) { wc2.Head.divided = Divided.Lead; wc3.Head.divided = Divided.Trail; } if (wt.divided == Divided.Lead) { wc2.Head.divided = Divided.Lead; wc3.Head.divided = Divided.Middle; } if (wt.divided == Divided.Middle) { wc2.Head.divided = Divided.Middle; wc3.Head.divided = Divided.Middle; } if (wt.divided == Divided.Trail) { wc2.Head.divided = Divided.Middle; wc3.Head.divided = Divided.Trail; } // wc2とwc3をつなぐ wc2.Add(wc3); // wc2---wc3 のコストを計算 int divChainCost = wc2.GetChainCost(); if (minimumCost >= divChainCost) { minimumCostChain = wc2; minimumCost = divChainCost; //最小コストの更新 } #if DEBUG_LOG KJ_Analyzer.WriteDebugLog("wc2:" + wc2.Head.word + "," + wc2.Head.Cost); KJ_Analyzer.WriteDebugLog("wc3:" + wc3.Head.word + "," + wc3.Head.Cost); KJ_Analyzer.WriteDebugLog("divChainCost:" + divChainCost); #endif target_len++; } // end of while // Chain中のwordが全て翻訳できていない if (minimumCostChain == null || (minimumCostChain != null && !minimumCostChain.IsTranslated())) { return(null); } // 翻訳できていない部分chainを再起実行 WordTable subT = minimumCostChain.Head; while (subT != null) { if (!subT.IsTranslated()) { WordChain subWc = WordPartProc(subT); if (subWc != null) { WordTable wNext = subT.next; minimumCostChain.Swap(subT, subWc); subT = wNext; continue; } } subT = subT.next; } return(minimumCostChain); }
//------------------------------------------------------- static private WordChain DivideJapanesePP(WordTable wTable) { StringDivider sd = new StringDivider(wTable.word); // 前から1文字ずつ落としつつ,検索。 string trans = ""; while (sd.eof() == false) { // 文字列を分割する HYAM.KJ_dict.Pair pair = sd.DivideForward(); if (Hangul.withPachim(pair.head)) { trans = KJ_Filter.SearchPP_Pachim(pair.tail); } else { trans = KJ_Filter.SearchPP_NoPachim(pair.tail); } if (trans == "") { continue; } SearchResult result = KJ_dict.SearchFull(pair.head); if (result != null) { // 助詞確定 // 助詞に先行しない語は除外 // 산은 (은が助詞なら、산は動詞[連体詞]ではない) // result = SearchResult.CheckPPConnectable(result); // もし語が全部落ちたならば何もしない if (result.documents.Count == 0) { // nop } else { // 先行語+助詞のチェーンを作る WordTable wt1 = new WordTable(pair.head); wt1.SetResult(result); wt1.divided = Divided.Lead; // wt2.transWord はまだ設定しない。 // 前の訳語のパッチムに影響されるため。 WordTable wt2 = new WordTable(pair.tail); wt2.posCategory = PosCategory.PP; wt2.divided = Divided.Trail; // 長い助詞ほどコストを低くする // wt2.Cost = 0; if (wt2.word.Length > 2) { wt2.Cost = 0; } else if (wt2.word.Length == 2) { wt2.Cost = 3; } else { wt2.Cost = 5; } WordChain rtnChain = new WordChain(wt1, wt2); return(rtnChain); } } } // end of while return(null); // 分離できなかったらnullを返す。 }