Lucene.net标准分词器在英文分词中有非常好的体验。比喻说:在邮件,IP地址,符号处理方面,它都处理得非常好。只是很遗憾,它不支持中文词组分词。于是,我就通过修改里面的核心代码让它扩展,支持中文的分词。
目标:使它能够增加对中文词组的切词。
效果:
原句:“我是中国人!I am chiness!Email:[email protected];IP:172.17.34.168”
切词效果:
我/是/中国人/中国/中/国/人/Email/[email protected]/IP/172.17.34.168
所要完成的任务:
1. 装载词库
2. 截取一段连续的中文字段
3. 进行连续的分词.
下面是设计扩展Lucene.net标准分词器的支持中文词组分词的流程图.
接下来,我把扩展Lucene.net标准分词器所写的核心代码,主要包含三个函数,它们分别实现装载词典,载取连续中文字段,中文词组分词算法功能.
#region 加载中文词典 public void LoadDirectory(string path) { if(!File.Exists("words.txt")) return; TextReader tr_words=new StreamReader("words.txt",System.Text.Encoding.Default); System.Diagnostics.Debug.Write("begin read words"); if(directory==null) { directory=new System.Collections.Hashtable(); try { string word=null; while((word=tr_words.ReadLine())!=null) { try { if(directory[word]==null) { directory.Add(word,word); } } catch(SystemException ex_) { } } } catch(SystemException ex) { } } #endregion } #region 截取一段连续中文字段 private void InitChinessText() { textlengh=0; cn_index=0; chinesstext[0]=token.image; textlengh++; cn_start=token.beginColumn; isCnToken=true; bool isCN= true; while(isCN&&textlengh<255) { token=token_source.GetNextToken(); if(token.kind!=0) { isCN=Char.GetUnicodeCategory(token.image,0).Equals(System.Globalization.UnicodeCategory.OtherLetter); } else isCN=false; if(isCN) { chinesstext[textlengh]=token.image; textlengh++; } else { cn_end_token=token; } } if(textlengh>=4) { wordlengh=4; } else wordlengh=textlengh; } #endregion #region 实现中文分词算法 private string GetNextTokenText() { string text=null; if(wordlengh==4) { text=chinesstext[cn_index]+chinesstext[cn_index+1]+chinesstext[cn_index+2]+chinesstext[cn_index+3]; if(directory[text]!=null) { } wordlengh--; } if(wordlengh==3) { text=chinesstext[cn_index]+chinesstext[cn_index+1]+chinesstext[cn_index+2]; wordlengh--; if(directory[text]!=null) { goto return_; } } if(wordlengh==2) { text=chinesstext[cn_index]+chinesstext[cn_index+1]; wordlengh--; if(directory[text]!=null) { goto return_; } } if(wordlengh==1) { text=chinesstext[cn_index]; cn_index++; if((textlengh-cn_index)>=4) { wordlengh=4; } else if((textlengh-cn_index)==0) { isCnToken=false; jj_ntk=cn_end_token.kind; token=new Token(); token.next=cn_end_token; } else { wordlengh=textlengh-cn_index; } } return_: return text; } #endregion */
一、中文分词方式:
中文分词几种常用的方式:
A. 单字分词
单字分词,顾名思义,就是按照中文一个字一个字地进行分词。如:我们是中国人,效果:我\们\是\中\国\人。
B. 二分法
二分法,就是按两个字进行切分。如:我们是中国人,效果:我们\们是\是中\中国\国人。
C. 词库分词
词库分词,就是按某种算法构造词然后去匹配已建好的词库集合,如果匹配到就切分出来成为词语。通常词库分词被认为是最理想的中文分词算法如:我们是中国人,通成效果为:我们\是\中国\中国人。
二、Lucene.net中五种中文分词效果探究
在Lucene.net中有很多种分词器,不同分词器使用了不同的分词算法,有不同的分词效果,满足不同的需求!在这里主要是看看其中五中分词器用来对中文切词的效果。五中分词器分别为:StandardTokenizer,CJKTokenizer,ChinessTokenizer,LowerCaseTokenizer,WhitespaceTokenizer;
下面就来测试一下它们切词的效果:
测试目标:是否支持中文词语,英文单词,邮件,IP地址,标点符号,数字,数学表达式的切割。
测试文字:“我们是中国人; 我们 是 人;we are chiness; 172.16.34.172;[email protected];#$*;85*34;58 69”
测试StandardTokenizer的分词情况如下: 我/ 们/ 是/ 中/ 国/ 人/ 我/ 们/ 是/ 人/ we/ are/ chiness/ 172.16.34.172/ [email protected]/ 85/ 34/ 58/ 69/ 测试CJKTokenizer的分词情况如下: 我们/ 们是/ 是中/ 中国/ 国人/ 我们/ 是/ 人/ we/ chiness/ 172/ 16/ 34/ 172/ youpe izun/ 126/ com/ #/ 85/ 34/ 58/ 69/ 测试ChinessTokenizer的分词情况如下: 我/ 们/ 是/ 中/ 国/ 人/ 我/ 们/ 是/ 人/ we/ are/ chiness/ 172/ 16/ 34/ 172/ youp eizun/ 126/ com/ 85/ 34/ 58/ 69/ 测试LowerCaseTokenizer的分词情况如下: 我们是中国人/我们/是/人/we/are/chiness/youpeizun/com/ 测试WhitespaceTokenizer的分词情况如下: 我们是中国人;/我们/是/人;we/are/chiness;/172.16.34.172;[email protected];#$*;85* 34;58/69/ |
测试代码:
三、 五中分词器代码设计探究
从下面分词器代码设计中的静态结构图可以清晰的看出其继承关系。无论是哪个分词器,其分词最终实现的算法都是在Next()方法,想深入了解,请看其相关源码。