对“大学生活”这句话做分词,通常来说,一个分词器会分三步来实现:
- 找到“大学生活”这句话中的全部词做为一个集合,即:[大、大学、大学生、学、学生、生、生活、活]
- 在第一步中得到的集合中找到所有能组合成“大学生活”这句话的子集,即:
[大、学、生、活]
[大、学、生活]
[大、学生、活]
[大学、生、活]
[大学、生活]
[大学生、活]
- 在第二步中产生的所有子集中挑选一个最有可能的作为最终的分词结果。
为了得到第1步需要的集合,通常我们需要一个词典。大部分的分词器都是基于词典去做分词的(也就是说也可以不基于词典来做分词,在此暂时不做讨论)。那么现在假设我们有一个小词典:[大学、大学生、学习、学习机、学生、生气、生活、活着]。首先要在“大学生活”这句话里面匹配到这个词典里面的全部词,有些同学脑中可能会出现这种过程:
public class Demo1{
//加载词典中的所有词汇
static Set<String> dic = new HashSet(){
{
add("大学");
add("大学生");
add("学习");
add("学习机");
add("学生");
add("生气");
add("生活");
add("活着");
}};
//匹配句子中词典中存在的所有词汇
static List<String> getAllWordsMatched(String sentence){
List<String> wordList = new ArrayList<>();
for(int index = 0;index < sentence.length();index++){
for(int offset = index+1; offset <= sentence.length();offset++){
String sub = sentence.substring(index,offset);
if(dic.contains(sub)){
wordList.add(sub);
}
}
}
return wordList;
}
public static void main(String[] args){
String sentence = "大学生活";
getAllWordsMatched(sentence).forEach(System.out::println);
}
}
执行这段代码会输出:
大学
大学生
学生
生活
似乎到这里,我们已经完美地完成了在词典中找到词的任务。然而真实的分词器的词典往往有几十万甚至几百万的词汇量,使用上面这种算法性能太低了。高效地实现这种匹配的算法有很多,下面简单介绍一种:
AC自动机(Aho-Corasick automaton)
AC自动机是一种常用的多模式匹配算法,基于字典树(trie树)的数据结构和KMP算法的失败指针的思想来实现,有不错的性能并且实现起来非常简单。
字典树(trie树)
引用一下百度百科对于trie树的描述:Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常