在CLucene-2.3.3.4中加入ICTCLAS实现中文分词

来源:互联网 发布:淘宝私人订制板块在哪 编辑:程序博客网 时间:2024/04/30 04:00

一、修改Mic中的两个编码转化函数

void Misc::_cpywideToChar(const wchar_t* s, char* d, size_t len){
    //size_t sLen = wcslen(s);
    //for ( uint32_t i=0;i<len&&i<sLen+1;i++ )
      //  d[i] = LUCENE_OOR_CHAR(s[i]);
    size_t ret=lucene_wcstoutf8(d,s,len);
}
void Misc::_cpycharToWide(const char* s, wchar_t* d, size_t len){
    //size_t sLen = strlen(s);
    //for ( uint32_t i=0;i<len&&i<sLen+1;i++ )
      //d[i] = s[i];
    size_t ret=lucene_utf8towcs(d,s,len);
}

更改如上,这个是使用config中utf8.cpp中的编码转化函数实现的

二、修改standardAnalysis.cpp中的函数

在函数Token* StandardTokenizer::next(Token* t)中,将_CJK的判定提前即:

if ( ch == 0 || ch == -1 ){
        continue;
      } else if (SPACE) {
        continue;
      }else if ( _CJK ){
        //本次读入的文本实在ReadCJK后才加入的,分词应在该函数之中进行
        t = ReadCJK(ch,t);

        if(t!=NULL)return t;

}

这些在其他博客中也有介绍,现在介绍更为细节的东西

三、添加一个函数

在跟进调试可以发现,在ReadCJK后,t中保存的是从文本中读取的中文字符,使用t->termBuffer()可以获取,这时字符是unicode编码的,我们调用ICTCLAS对其分词时需要转化为char类型的,因为ICTCLAS只能处理char类型的字符串,如

    int len;
    //将宽字符转化为char型
    STRCPY_TtoA(trans,t->termBuffer(),LUCENE_MAX_WORD_LEN);
        //取得欲分词字符串的长度,并分配临时数组,大小为将分字符串长度的6倍
    len=strlen(trans);
        //使用中科大分词软件分词,并得到分词的个数
    nRes=ICTCLAS_ParagraphProcess(trans,len,tResult,CODE_TYPE_UTF8,0);

此段代码可以插在t=ReadCJK(ch,t)之后,现在就有一个问题了,我们怎么保证在每次调用next的时候返回一个分词结果,在下次调用的时候还能接着返回本次没有返回完的结果,这就需要我们加入一个控制函数,能够判定本次的分词有没有返回完,定义函数:Token* getCJK(Token* t).


为了能够判定我们需要定义几个全局变量,定义在strandardAnalysis.h中,一个是我们的词分结果tResult,另一是我们的分词后字符串长度nRes,还有我们返回的当前位置end,函数如下:

  Token* StandardTokenizer::getCJK(Token* t) {        
    TCHAR word[LUCENE_MAX_WORD_LEN]={0};
    char cword[LUCENE_MAX_WORD_LEN]={0};
    int i=0;
    while(tResult[end]!=' '&&end<nRes){
        cword[i++]=tResult[end];
    end++;
    }
    cword[end+1]=0;
    while(tResult[end]!=' '&&end<nRes)end++;//找到下一次的开头
    printf("%s\n",cword);
    if(tResult[end]==' ')end++;
    STRCPY_AtoT(word,cword,LUCENE_MAX_WORD_LEN);
    t->setText(word);  
    if ( t != NULL ) return t;
    return NULL;
  }

这个函数定义好之后,我们只需要在每次进入next函数的时候加一个判定条件就可以了,如下:

    if(end<nRes){
        //调用函数获得一个分词
    return getCJK(t);
    }

    else{
      tResult[0]=0;
      end=nRes=0;
      while (!EOS) {

记得在下一次的时候要初始化一下参数!!

四、文件配置及测试

在standardAnalysis.cpp中加入头文件

////////////////////////////////////
#include "CLucene/config/repl_tchar.h"
#include "CLucene/config/repl_wchar.h"
#include "CLucene/util/Misc.h"
#define OS_LINUX
#include "CLucene/ICTCLAS50.h"
///////////////////////////////////

可以用src中的demo进行测试,

1.可以将libICTCLAS50.so复制到bin/文件下,

2.头文件ICTCLAS50.h复制到core\CLucene目录下,

3.改动demo/CMakeFiles/cl_demo.dir/目录下的link.txt文件,加入-L../../bin -lICTCLAS50动态链接库,

4.改动demo/文件下的IndexFiles.cpp及SearchFiles.cpp中的解析器的定义,定义为standard::StandardAnalyzer类型

这样重新编译make cl_demo再在bin/目录下运行./cl_demo就可以了


clucene在linux下的编译,可以参考我的另一篇博客

0 0
原创粉丝点击