一个简单的中文分词


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;

import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.Tokenizer;


public class XiaoMaTokenizer extends Tokenizer{

/**
* 用来缓存词典里所有的词
*/
private TreeMap<String, String> allWordsMap ;

/**
* 读入的所有文本(待分词的文本) buffer
*/
StringBuffer textBuffer = null ;

/**
* 读入的所有文本(待分词的文本) string
*/
private String text = null ;

/**
* 要分词的文本字符的长度
*/
private int textLength ;


/**
* 存放token序列的序列
*/
private List<Token> allTokenList = null ;

/**
* token序列的迭代
*/
private Iterator<Token> allTokenIter = null ;

/**
* 匹配当前的字符串偏移量
*/
private int curIndex = 0 ;

/**
* 最长词的长度
*/
private static int MAX_WORD_LENGTH = 10 ;

/**
* 切词的长度
*/
private int cutLength = 0 ;


public XiaoMaTokenizer(Reader input){
this.input = input ;
try{
//初始化
init() ;
//正向最大匹配
//doCutFirst() ;
//逆向的最大匹配
doCutLast() ;

allTokenIter = allTokenList.iterator() ;
}catch(Exception e){
e.printStackTrace() ;
}
}

/**
* 初始化数据
* 导入词库
* 读出要分词的字符串
*
*/
public void init() throws IOException{
//导入该公司的词库
loadWords() ;

//读入要分词的文本
textBuffer = new StringBuffer() ;
BufferedReader br = new BufferedReader(input) ;
String temp = null ;
while(true){
if((temp = br.readLine())!= null){
textBuffer.append(temp) ;
}else{
break ;
}
text = new String(textBuffer) ;
textLength = textBuffer.length() ;
}
allTokenList = new ArrayList<Token>() ;
}

/**
* 正向最大匹配
*/
public void doCutFirst(){
//开始的时候从0开始
curIndex = 0 ;
while(curIndex < textLength){
//如果切词长度为0,则设定切词长度
if(cutLength == 0 ){
//设定正向的切词长度
setCutFirstLength() ;
}
int startIndex = curIndex;
int endIndex = curIndex + cutLength;
String temp = textBuffer.substring(startIndex , endIndex) ;
//如果存在这个词,将偏移量移动这个词的距离
if(allWordsMap.containsKey(temp)){
Token tk = new Token(temp,startIndex,endIndex) ;
allTokenList.add(tk) ;
curIndex += cutLength ;
//将切词长度置零,下次循环时可以重新设定长度
cutLength = 0 ;
}else{
//如果不存在这个词,则将切词长度减1
cutLength -- ;
if(cutLength == 0){
curIndex++ ;
cutLength =0 ;
}
}
}
}

/**
* 逆向最大匹配
*/
public void doCutLast(){
// 开始的时候从最后的索引开始
curIndex = textLength ;
while(curIndex > 0){
//如果切词长度为0,则设定切词长度
if(cutLength == 0 ){
//设定逆向的切词长度
setCutLastLength() ;
}
int startIndex = curIndex - cutLength;
int endIndex = curIndex;
String temp = textBuffer.substring(startIndex , endIndex) ;
//如果存在这个词,将偏移量向前移动这个词的距离
if(allWordsMap.containsKey(temp)){
Token tk = new Token(temp,startIndex,endIndex) ;
allTokenList.add(tk) ;
curIndex -= cutLength ;
//将切词长度置零,下次循环时可以重新设定长度
cutLength = 0 ;
}else{
//如果不存在这个词,则将切词长度减1
cutLength -- ;
if(cutLength == 0){
curIndex-- ;
//将切词长度置零,下次循环时可以重新设定长度
cutLength = 0 ;
}
}
}
}

/**
* 设定正向最大匹配的切词长度
*
*/
private void setCutFirstLength(){
//如果文本长度没有达到设定的最大长度,那么直接从文本最后开始切
if(textLength <= MAX_WORD_LENGTH){
//文本长度没有达到设定的最大长度,切词长度从文本的长度开始
cutLength = textBuffer.length() ;
}else{
//文本长度达到设定的最大长度,切词长度从设定的最大长度开始
cutLength = MAX_WORD_LENGTH ;
}
//如果切词长度大于从当前偏移量到文本最后的长度,那么切词长度应该是最后剩下的文本长度
if(cutLength > textLength - curIndex){
cutLength =textLength - curIndex ;
}


}

/**
* 设定逆向最大匹配的切词长度
*
*/
private void setCutLastLength(){
//如果文本长度没有达到设定的最大长度,那么切词长度就是文本长度
if(textLength <= MAX_WORD_LENGTH){
//文本长度没有达到设定的最大长度,切词长度从文本的长度开始
cutLength = textBuffer.length() ;
}else{
//文本长度达到设定的最大长度,切词长度从设定的最大长度开始
cutLength = MAX_WORD_LENGTH ;
}
//如果当前偏移量小于切词长度,则切词长度应该是偏移量
if(cutLength > curIndex){
cutLength = curIndex ;
}


}


@Override
public Token next() throws IOException{
while(allTokenIter.hasNext()){
return allTokenIter.next() ;
}
return null ;
}

/*导入词库,对每个公司,都有一个专门的词库(关键词表)*/
public void loadWords(){
if(allWordsMap != null){
return ;
}
allWordsMap = new TreeMap<String,String>() ;
try{
File file = new File("sDict.txt") ;
System.out.println(file.getAbsolutePath()) ;
InputStream words = new FileInputStream(file) ;
BufferedReader in = new BufferedReader(new InputStreamReader(words,"UTF-8")) ;
String word = null ;
while((word = in.readLine())!=null){
allWordsMap.put(word, "key") ;
}
allWordsMap.put("123", "1") ;
}catch(IOException e){
e.printStackTrace() ;
}
}


public static void main(String [] args){
long stime = System.currentTimeMillis() ;
StringReader sr = new StringReader("测试中文分词,这里填写要分词的句子") ;
Tokenizer xt = new XiaoMaTokenizer(sr) ;
Token t = null ;
try{
while((t=xt.next())!=null){
System.out.println(t) ;
}
}catch(Exception e){
e.printStackTrace() ;
}
long etime = System.currentTimeMillis() ;
System.out.println("用时:" + (double)(etime-stime)/1000);
}


}


中文分词是自然语言处理的一个重要任务,可以通过CRF(条件随机场)模型来训练一个中文分词模型。以下是一个基于Python的示例代码,使用jieba分词库和sklearn-crfsuite包进行中文分词模型训练。 首先,需要准备训练数据。可以使用已经标注好的中文分词语料库,例如pku和msr语料库。数据格式为每行一个句子,句子中的词语之间用空格隔开,词语后面跟着词性标记,例如: ``` 我 爱 北京 天安门/n ``` 其中,`/n`表示“名词”。这样的标注格式可以使用jieba分词库的`cut`函数进行分词,并将分词结果与标注比较,得到标注序列。 ``` python import jieba def cut_sentence(sentence): return [word for word in jieba.cut(sentence)] def get_labels(sentence, labels): words = cut_sentence(sentence) return [labels[word] for word in words] with open('train_data.txt', 'r') as f: train_data = f.readlines() train_sentences = [] train_labels = [] labels = {} for sentence in train_data: sentence = sentence.strip() words = sentence.split(' ') train_sentences.append(cut_sentence(sentence)) for word in words: if '/n' in word: word, label = word[:-2], word[-2:] labels[word] = label train_labels.append(get_labels(sentence, labels)) ``` 得到训练数据后,可以使用sklearn-crfsuite包来训练CRF模型。 ``` python from sklearn_crfsuite import CRF model = CRF() model.fit(train_sentences, train_labels) ``` 训练完成后,可以使用训练好的模型进行分词。 ``` python test_sentence = '我爱北京天安门' test_sentence_words = cut_sentence(test_sentence) test_features = [[{'word': word}] for word in test_sentence_words] test_labels = model.predict(test_features) results = [] for i in range(len(test_sentence_words)): result = test_sentence_words[i] + '/' + test_labels[0][i] results.append(result) print(' '.join(results)) ``` 输出结果为: ``` 我/r 爱/v 北京/ns 天安门/ns ``` 其中,`/r`表示“代词”,`/v`表示“动词”,`/ns`表示“地名”。这个分词结果和标注完全一致。 这是一个简单中文分词模型训练示例,实际应用中还需要进行更多的优化和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值