1. 程式人生 > >自己動手寫分詞引擎——逆向最大、正向最大、雙向最大分詞演算法的實現

自己動手寫分詞引擎——逆向最大、正向最大、雙向最大分詞演算法的實現

分詞引擎已經是NLP最成熟的部分了,經歷了:字典分詞,統計分詞等發展之後,除了應付學術中才有的各種變態歧義句之外,目前工業界的分詞引擎對於絕大多數的常見問題已經足以應對,頂多是需要不斷優化新詞字典就可以了。

但不管怎麼樣,對於一個NLPer還是要能夠手寫最簡單的分詞演算法的,這也是面試必備基本功。

一,基於字典的逆向最大分詞演算法

從後向前讀入待分詞字串,讀入字串的長度由分詞字典中最長單詞決定。

之後測試讀入的字串是否存在在字典中,如果存在的話,從原始文字中刪除這個字串,開始重複。

如果讀入的字串不存在在字典中,從左向右減小其長度重複在字典中查詢,如此迴圈。

具體如下例所示:

輸入:我一個人吃飯,
第一次匹配:一個人吃飯
個人吃飯
人吃飯
吃飯 ====》得到一個詞–——吃飯

第二次匹配:我一個人
一個人
個人 ====》得到一個詞—— 個人

第三次匹配:我一
一  ====》得到一個詞– 一


第四次匹配:我  ====》得到一個詞– 我

最後反向最大匹配的結果是:
/我/一/個人/吃飯/

下面上程式碼:

public static void ReverseMaxSegmentation(String input) {
        if(dictionary.isEmpty()) {
            initDictionary();
        }
        
        StringBuffer result = new StringBuffer();       
        while(input.length()>0) {
            String temp;
            //temp就是待分詞的短語
            if( input.length()<max_words ) {
                temp = input;
            }else {
                temp = input.substring(input.length() - max_words);
            }
            
            while(temp.length()>0) {
                if(dictionary.get(temp)!=null || temp.length()==1) {
                    //如果在字典中找到某個詞,這個詞被加入到分詞結果中同時從原始輸入中刪除這個詞
                    result = new StringBuffer(temp).append("/").append(result);
                    input = input.substring(0, input.length() - temp.length());
                    break;
                }
                else{
                	//待分詞短語從左向右不斷變短
                    temp = temp.substring(1);
                }
            }
        }
        System.out.println(result);
}

二,基於字典的正向最大分詞

和逆向正好相反,從輸入Strign的最開始開始讀入待分詞短語,在字典中查詢,如果找不到的話將分詞短語變短,如此迴圈。

變短的時候和逆向分詞相反,從右向左逐步變短。

正向最大匹配方式,最大長度為5
第一次讀入:我一個人吃
我一個人
我一個
我一
我  ====》得到一個詞– 我
第二次讀入:一個人吃飯
一個人吃
一個人
一個 ====》得到一個詞– 一個
第三次讀入:人吃飯
人吃
人 ====》得到一個詞– 人
最後一次讀入:吃飯
====》得到一個詞– 吃飯
最後正向最大匹配的結果是:/我/一個/人/吃飯/

程式碼如下所示:

    public static void ForwardMaxSegmentation(String input) {
        if(dictionary.isEmpty()) {
            initDictionary();
        }
        
        StringBuffer result = new StringBuffer();
        
        while(input.length()>0) {
            String temp;
            if( input.length()<max_words ) {
                temp = input;
            }else {
                temp = input.substring(0, max_words);
            }
            while(temp.length()>0) {
                if(dictionary.get(temp)!=null || temp.length()==1) {
                    result = result.append(temp).append("/");
                    input = input.substring(temp.length());
                    break;
                }
                else{
                    temp = temp.substring(0,temp.length()-1);
                }
            }
        }
        System.out.println(result);
    }