基本分詞

中文分詞有不少算法,同時大都是基於四種基本的分詞方式,在基本的分詞基礎上作一些歧義消除、未登陸詞識別等功能。java

下面以「南京市長江大橋」爲例,分享一下四種基本的分詞算法

正向最大匹配code

從字面就很好理解,就是一句話從頭開始讀,可着最長的詞取。get

// 南京市長江大橋 --> 南京市 長江大橋

代碼io

List<Word> segmentation(String text) {
        Queue<Word> results = new LinkedList<>();
        int textLength = text.length();
        // 設置詞的最大長度,詞庫中最長詞的長度跟目標句子長度中,取最小
        int wordMaxLength = min(DictionaryFactory.getDictionary().getMaxWordLength(), textLength);
        int start = 0; // 開始分詞的位置

        while (start < textLength) {
            int currentLength = min(textLength - start, wordMaxLength); // 未分詞的句子長度
            boolean isSeg = false;
            while (start + currentLength <= textLength) {
                if (DictionaryFactory.getDictionary().contains(text, start, currentLength)) {
                    addWord(results, text, start, currentLength); // 成功分詞  加入results中
                    isSeg = true;
                    break;
                } else if (--currentLength <= 0) { // 剩餘長度爲0 跳出當前循環
                    break;
                }
            }

            if (isSeg) {
                start += currentLength;
            } else {
                addWord(results, text, start++, 1); // 沒有分出詞  單字成詞
            }
        }

        return new ArrayList<>(results);
    }

結果class

正向最小匹配登錄

跟上邊的正好造成對比,這個也是正向,可是是可着最小的詞先分基礎

// 南京市長江大橋 --> 南京 市長 江 大橋

代碼List

List<Word> segmentation(String text) {
        Queue<Word> results = new LinkedList<>();
        int textLength = text.length();
        int wordMinLength = 2; //最小詞長 這裏不考慮單字的詞
        int start = 0;

        while (start < textLength) {
            int currentLength = wordMinLength; // 從start處開始 從長度爲2開始查找可分的詞
            boolean isSeg = false;
            while (start + currentLength <= textLength) {
                if (DictionaryFactory.getDictionary().contains(text, start, currentLength)) {
                    addWord(results, text, start, currentLength);
                    isSeg = true;
                    break;
                } else if (++currentLength > DictionaryFactory.getDictionary().getMaxWordLength()) { // 沒有的話就讓currentLength+1,若是大於詞典中最長的詞就跳出循環
                    break;
                }
            }

            if (isSeg) {
                start += currentLength;
            } else {
                addWord(results, text, start++, 1);
            }
        }

        return new ArrayList<>(results);
    }

結果循環

逆向最大匹配

也是可着最大的詞先分,不過是從後往前開始分

// 南京市長江大橋 --> 南京市 長江大橋

代碼

public List<Word> segmentation(String text) {
        Deque<Word> results = new ArrayDeque<>();
        int wordMaxLength = min(DictionaryFactory.getDictionary().getMaxWordLength(), text.length());
        int end = text.length();

        while (end > 0) {
            int currentLength = min(wordMaxLength, end);
            boolean isSeg = false;
            while (end - currentLength >= 0) {
                if (DictionaryFactory.getDictionary().contains(text, end - currentLength, currentLength)) {
                    addWord(results, text, end - currentLength, currentLength);
                    isSeg = true;
                    break;
                } else if (--currentLength <= 0) {
                    break;
                }
            }

            if (isSeg) {
                end -= currentLength;
            } else {
                addWord(results, text, --end, 1);
            }
        }

        return new ArrayList<>(results);
    }

結果

逆向最小匹配

正向最小匹配倒過來便可

// 南京市長江大橋 --> 南京市 長江 大橋

代碼

public List<Word> segmentation(String text) {
        Deque<Word> results = new ArrayDeque<>();
        int wordMinLength = 2;
        int end = text.length();

        while (end > 0) {
            int currentLength = wordMinLength;
            boolean isSeg = false;
            while (end - currentLength >= 0) {
                if (DictionaryFactory.getDictionary().contains(text, end - currentLength, currentLength)) {
                    addWord(results, text, end - currentLength, currentLength);
                    isSeg = true;
                    break;
                } else if (++currentLength > DictionaryFactory.getDictionary().getMaxWordLength()) {
                    break;
                }
            }

            if (isSeg) {
                end -= currentLength;
            } else {
                addWord(results, text, --end, 1);
            }
        }

        return new ArrayList<>(results);
    }

結果

相關文章
相關標籤/搜索