中文分詞有不少算法,同時大都是基於四種基本的分詞方式,在基本的分詞基礎上作一些歧義消除、未登陸詞識別等功能。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); }
結果