中文分词有很多算法,同时大都是基于四种基本的分词方式,在基本的分词基础上做一些歧义消除、未登录词识别等功能。 下面以“南京市长江大桥”为例,分享一下四种基本的分词
中文分词有很多算法,同时大都是基于四种基本的分词方式,在基本的分词基础上做一些歧义消除、未登录词识别等功能。
下面以“南京市长江大桥”为例,分享一下四种基本的分词
正向最大匹配
从字面就很好理解,就是一句话从头开始读,可着最长的词取。
// 南京市长江大桥 --> 南京市 长江大桥
代码
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); }
结果
正向最小匹配
跟上边的正好形成对比,这个也是正向,但是是可着最小的词先分
// 南京市长江大桥 --> 南京 市长 江 大桥
代码
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); }
结果