Beispiel #1
0
        //--------------------------------------------------------------------
        // 完全一致の辞書検索 (再起にすると時間がかかりすぎるので再起なし)
        //
        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);
        }
Beispiel #2
0
        //-------------------------------------------------------
        //  分割なし完全一致の語
        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);
        }
Beispiel #3
0
        //------------------------------------------------------------------
        // 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);
        }
Beispiel #4
0
        //------------------------------------------------------------------
        // 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);
        }
Beispiel #5
0
        //--------------------------------------------------------------
        // 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);
        }
Beispiel #6
0
        //--------------------------------------------------------------------
        // 語の変換   (語の分解あり)
        //   語分解で翻訳済み末尾がずれることがあるので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);
        }
Beispiel #7
0
        //-------------------------------------------------------
        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を返す。
        }