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