试着写 搜索算法-- 最大逆向匹配分词算法

     最近想试着自己实现一些搜索算法,受到http://www.52nlp.cn/maximum-matching-method-of-chinese-word-segmentation这位大湿的一点启发,准备用JAVA把算法实现了一遍,代码写的有些简单,请各位大神指正,

     正向最大匹配法算法思想如下所示:

(注:以上最大匹配算法图来自于詹老师讲义)
  逆向匹配法思想与正向一样,只是从右向左切分,这里举一个例子:
   输入例句:S1=”计算语言学课程有意思” ;
   定义:最大词长MaxLen = 5;S2= ” “;分隔符 = “/”;
   假设存在词表:…,计算语言学,课程,意思,…;
   最大逆向匹配分词算法过程如下:
 (1)S2=”";S1不为空,从S1右边取出候选子串W=”课程有意思”;
 (2)查词表,W不在词表中,将W最左边一个字去掉,得到W=”程有意思”;
 (3)查词表,W不在词表中,将W最左边一个字去掉,得到W=”有意思”;
 (4)查词表,W不在词表中,将W最左边一个字去掉,得到W=”意思”
 (5)查词表,“意思”在词表中,将W加入到S2中,S2=” 意思/”,并将W从S1中去掉,此时S1=”计算语言学课程有”;
 (6)S1不为空,于是从S1左边取出候选子串W=”言学课程有”;
 (7)查词表,W不在词表中,将W最左边一个字去掉,得到W=”学课程有”;
 (8)查词表,W不在词表中,将W最左边一个字去掉,得到W=”课程有”;
 (9)查词表,W不在词表中,将W最左边一个字去掉,得到W=”程有”;
 (10)查词表,W不在词表中,将W最左边一个字去掉,得到W=”有”,这W是单字,将W加入到S2中,S2=“ /有 /意思”,并将W从S1中去掉,此时S1=”计算语言学课程”;
 (11)S1不为空,于是从S1左边取出候选子串W=”语言学课程”;
 (12)查词表,W不在词表中,将W最左边一个字去掉,得到W=”言学课程”;
 (13)查词表,W不在词表中,将W最左边一个字去掉,得到W=”学课程”;
 (14)查词表,W不在词表中,将W最左边一个字去掉,得到W=”课程”;
 (15)查词表,“意思”在词表中,将W加入到S2中,S2=“ 课程/ 有/ 意思/”,并将W从S1中去掉,此时S1=”计算语言学”;
 (16)S1不为空,于是从S1左边取出候选子串W=”计算语言学”;
 (17)查词表,“计算语言学”在词表中,将W加入到S2中,S2=“计算语言学/ 课程/ 有/ 意思/”,并将W从S1中去掉,此时S1=”";

 (18)S1为空,输出S2作为分词结果,分词过程结束。

      第一步,加载词库,词库大家可以随便找一些分词,可以去搜狗下载他的分词,自己整理一下就可以了,每一行一个词或者"#"分割;加载词库代码如下Dictionary类如下:

package com.seg.seg;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

public class Dictionary {
	private static Dictionary instance;
	/**
	 * 单例实现此类
	 * @return Dictionary
	 */
	public static Dictionary getInstance() {
		if (instance == null) {
			instance = new Dictionary();
			return instance;
		}
		return instance;
	}

	private static Map dic = new HashMap(
			160000);

	public boolean match(String word) {
		if (dic.containsKey(word)) {
			return Boolean.TRUE;
		}
		return Boolean.FALSE;
	}
	/**
	 * 构造函数初始化词库
	 */
	public Dictionary() {
		InputStream is = this.getClass().getClassLoader()
				.getResourceAsStream("main2012.dic");
		if (is != null) {
			try {
				BufferedReader br = new BufferedReader(new InputStreamReader(
						is, "UTF-8"));
				String theWord = null;
				do {
					theWord = br.readLine();
					if (theWord != null && !theWord.trim().isEmpty()
							&& theWord.trim().charAt(0) != '#') {
						dic.put(theWord.trim().toLowerCase().toString(), 1);
						// System.out.println(theWord.trim().toLowerCase().toCharArray());
					}
				} while (theWord != null);

			} catch (IOException ioe) {
				System.err.println(" Dictionary loading exception。ClassName: ");
				ioe.printStackTrace();

			} finally {
				try {
					if (is != null) {
						is.close();
						is = null;
						System.out.print("词库加载完成");
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

}

第二步,加载完词库后,就可以实现分词算法了,代码如下:

package com.seg.seg;

import java.util.ArrayList;
import java.util.List;

public class Segmentation {

	/**
	 * 测试结果
	 * @param args
	 */
	public static void main(String[] args) {
		Segmentation s=new Segmentation();
		 System.out.print(s.getSegWords("又一个能和大家无障碍沟通的渠道,想聊天的都加起来啊"));
	}
	/**
	 * 分词主方法
	 * @param words
	 * @return
	 */
	List getSegWords(String words) {
		int length=0;
		String nowWords="";
		List resultWord = new ArrayList();
		while((length=words.length()) !=0) {
		int maxl=5;
		if(maxl >length){
			maxl=length;
		}
		nowWords = words.substring(length -maxl, length);
		while(!Dictionary.getInstance().match(nowWords)){
			if(maxl ==1){		
			break;
			}
			maxl--;
			nowWords = words.substring(length -maxl, length);
		} 
			words=words.substring(0,length -maxl);
			resultWord.add(nowWords);
		}
		return resultWord;
		
	}
}


测试结果如下:

词库加载完成[来啊, 起, 加, 都, 的, 聊天, 想, ,, 渠道, 的, 沟通, 无障碍, 大家, 和, 能, 又一个]


只是做了简单的实现,标点符号都没有过滤,有时间我再慢慢加载内容

你可能感兴趣的:(算法设计,java,语言,搜索引擎)