分词引擎已经是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);
}