最近写了一个后项最大匹配的分词,其中构件词表的过程是参考了网上的一个已经有了的分词程序;
代码如下:(其中有两个词表文件interpunction.txt和simplexu8.txt,其中前者是用来定义过滤其中的一些特殊符号,后者是词表文件)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Locale;
import java.util.TreeMap;
import java.util.TreeSet;
import java.io.File;
import java.io.FileInputStream;
public class mySplitter
{
private boolean flag; //判断是否处理类似空格,标点等符号
private TreeSet interpunction; //标点符号的集合,用来过滤输入字符串的标点符号
private static TreeSet CJK = new TreeSet(); //存放中文词的集合
private static int maxlength = 0; //词典中最长的词的长度
static //构造中文词集合
{
String newword = null;
try
{
File file = new File("simplexu8.txt");
FileInputStream in0 = new FileInputStream(file);
BufferedReader in = new BufferedReader(new InputStreamReader(in0,"UTF-8"));
in.readLine();
maxlength = Integer.parseInt(in.readLine().toString()); //获取最大长度
//System.out.println(maxlength);
while ((newword = in.readLine()) != null)
{
CJK.add(newword.intern());
//System.out.println(newword.intern());
}
in.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
public mySplitter() //默认实现标点符号过滤
{
this.flag = true;
this.interpunction = new TreeSet();
this.init();
}
public mySplitter(boolean flag) //flag为true时实现标点符号过滤,否则不过滤标点符号
{
this.flag = flag;
this.interpunction = new TreeSet();
if(flag)
this.init();
}
public String split(String s , String seprator) //对指定的字符串s进行切分,切分出来的词用指定的字符串seprator进行分隔
{
if(s.length() <= 0)
return null;
StringBuffer result = new StringBuffer(); //存放最终返回结果
StringBuffer cur_word = new StringBuffer(); //存放当前正在处理的字符串
int cur_pos = s.length() - 1; //存放当前处理位置(在s中)
char cur_char = s.charAt(cur_pos);
while(isInterpunction(cur_char) && cur_pos > 0) //防止最后一个词是标点符号(如果是不处理标点符号,则isInterpunction函数可以保证结果的正确性)
{
cur_pos--;
cur_char = s.charAt(cur_pos);
}
if(isInterpunction(cur_char) && cur_pos == 0)
return null;
cur_word.insert(0, cur_char);
if(isCJK(cur_char)) //如果输入中文字符进行特殊对待,因为下面的中文处理算法在处理中文的时候不占用这个缓冲区cur_word
{
cur_pos++;
cur_word.setLength(0);
}
while(cur_pos > 0) //进行核心处理
{
cur_pos--;
cur_char = s.charAt(cur_pos);
if(isCJK(cur_char)) //匹配中文词
{
if(cur_word.length() > 0) //如果缓冲区中有词,先输出到结果中,因为处理中文时候不占用缓冲区cur_word
{
result.append(cur_word.toString() + seprator);
cur_word.setLength(0);
}
if(cur_word.length() <= 0)
{
int len = (maxlength - 1) > cur_pos ? cur_pos : (maxlength - 1); //防止处理到文章的最前面了
int i = 0;
while(i < len) //进行后项最大匹配
{
String a = s.substring(cur_pos - len + i , cur_pos + 1); //不断缩小匹配的长度,直到匹配成功
if(CJK.contains(a)) //判断是否成词
{
result.append(a + seprator);
cur_pos = cur_pos - len + i;
//System.out.println("if内 : "+a);
break;
}
i++;
}
if(i == len) //如果没有匹配的词
{
result.append(s.substring(cur_pos , cur_pos + 1) + seprator);
//System.out.println("i=len : "+s.substring(cur_pos , cur_pos + 1));
}
}
continue;
}
else if(isInterpunction(cur_char)) //过滤标点符号(如果是不处理标点符号,则isInterpunction函数可以保证结果的正确性)
{
if(cur_word.length() > 0)
{
result.append(cur_word.toString() + seprator);
cur_word.setLength(0);
}
continue;
}
else //处理数字,英文单词
{
cur_word.insert(0, cur_char);
continue;
}
}
if(cur_word.length() > 0)
{
result.append(cur_word.toString() + seprator);
cur_word.setLength(0);
}
return result.toString();
}
private void init() //初始化interpunction集合
{
String dataline;
try
{
InputStream data = getClass().getResourceAsStream("interpunction.txt");
BufferedReader in = new BufferedReader(new InputStreamReader(data, "UTF-8"));
in.readLine();
while ((dataline = in.readLine()) != null)
{
if (dataline.length() == 0)
{
continue;
}
this.interpunction.add(dataline.intern());
//System.out.println(dataline.intern());
}
in.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public boolean getFlag()
{
return this.flag;
}
public void setFlag(boolean flag)
{
this.flag = flag;
}
private boolean isCJK(char c)
{
if(Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS)
{
return true;
}
return false;
}
private boolean isInterpunction(char c)
{
if(this.flag)
{
return this.interpunction.contains(new Character(c).toString().intern());
}
return false;
}
public static void main(String args[])
{
mySplitter t = new mySplitter();
System.out.println(t.split(" jasd 我的天堂" , "#"));
}
}