自然语言处理

天书般的ICTCLAS分词系统代码(一)

字号+ 作者:hanyufeng 来源: 2021-10-04 15:55:00 我要评论( ) 阅读:

天书般的ICTCLAS分词系统代码(一)...

ICTCLAS分词系统是由中科院计算所的张华平、刘群所开发的一套获得广泛好评的分词系统,该版的Free版开放了源代码,为初学者提供了宝贵的学习材料。我们可以在“http://sewm.pku.edu.cn/QA/”找到FreeICTCLASLinux.tar的C++代码。 

可是目前该版本的ICTCLAS并没有提供完善的文档,所以阅读起来有一定的难度,所幸网上可以找到一些对ICTCLAS进行代码分析的文章,对理解分词系统的内部运行机制提供了很大的帮助。这些文章包括: 

1)http://blog.csdn.net/group/ictclas4j/;《ICTCLAS分词系统研究(一)~(六)》作者:sinboy。 

2)http://qxred.yculblog.com/post.1204714.html;《ICTCLAS 中科院分词系统 代码 注释 中文分词 词性标注》作者:风暴红QxRed 。 

按照上面这些文章的思路去读ICTCLAS的代码,可以比较容易的理顺思路。然而在我阅读代码的过程中,越来越对ICTCLAS天书般的代码感到厌烦。我不得不佩服中科院计算所的人思维缜密,头脑清晰,能写出滴水不漏而又让那些“头脑简单”的人百思不得其解的代码。将一件本来很简单的事情做得无比复杂…………

ICTCLAS中有一个名为CDynamicArray的类,存放在DynamicArray.cpp与DynamicArray.h两个文件中,这个DynamicArray是干什么用的?经过一番研究后终于明白是一个经过排序的链表。为了表达的更明白些,我们不妨看下面这张图:

(图一)

上面这张图是一个按照index值进行了排序的链表,当插入新结点时必须确保index值的有序性。DynamicArray类完成的功能基本上与上面这个链表差不多,只是排序规则不是index,而是row和col两个数据,如下图:

(图二) 

大家可以看到,这个有序链表的排序规则是先按row排序,row相同的按照col排序。当然排序规则是可以改变的,如果先按col排,再按row排,则上面的链表必须表述成:

(图三) 

在了解了这些内容的基础上,不妨让我们看看ICTCLAS中DynamicArray.cpp中的代码实现(这里我们只看GetElement方法的实现,其基本功能为给出row与col,然后将对应的元素取出来)。

DynamicArray.cpp

ELEMENT_TYPE CDynamicArray::GetElement(int nRow, int nCol, PARRAY_CHAIN pStart, 
  PARRAY_CHAIN *pRet) 
{ 
  PARRAY_CHAIN pCur = pStart; 
  if (pStart == 0) 
    pCur = m_pHead; 
  if (pRet != 0) 
    *pRet = NULL; 
  if (nRow > (int)m_nRow || nCol > (int)m_nCol) 
  //Judge if the row and col is overflow 
    return INFINITE_VALUE; 
  if (m_bRowFirst) 
  { 
    while (pCur != NULL && (nRow !=  - 1 && (int)pCur->row < nRow || (nCol !=   
      - 1 && (int)pCur->row == nRow && (int)pCur->col < nCol))) 
    { 
      if (pRet != 0) 
        *pRet = pCur; 
      pCur = pCur->next; 
    } 
  } 
  else 
  { 
    while (pCur != NULL && (nCol !=  - 1 && (int)pCur->col < nCol || ((int)pCur 
      ->col == nCol && nRow !=  - 1 && (int)pCur->row < nRow))) 
    { 
      if (pRet != 0) 
        *pRet = pCur; 
      pCur = pCur->next; 
    } 
  } 
  if (pCur != NULL && ((int)pCur->row == nRow || nRow ==  - 1) && ((int)pCur 
    ->col == nCol || nCol ==  - 1)) 
  //Find the same position 
  { 
    //Find it and return the value 
    if (pRet != 0) 
      *pRet = pCur; 
    return pCur->value; 
  } 
  return INFINITE_VALUE; 
}

这里我先要说明的是程序中的m_bRowFirst变量,它表示是先按row大小排列还是先按col大小排列。如果m_bRowFirst为逻辑真值,那么链表就如上面图二所示,如果为假,则如图三所示。

除了这个外,看到上面长长的条件表达式,你一定会吓坏了吧!更让人吓坏的是调用这段程序的代码:

对GetElement方法的调用

//来自NShortPath.cpp中ShortPath方法 
eWeight = m_apCost->GetElement( -1, nCurNode, 0, &pEdgeList); 
 
//来自Segment.cpp中BiGraphGenerate方法 
aWord.GetElement(pCur->col, -1, pCur, &pNextWords);//Get next words which begin with pCur->col

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 天书般的ICTCLAS分词系统代码(二)

    天书般的ICTCLAS分词系统...

  • 实现ICTCLAS到C#平台的移植

    实现ICTCLAS到C#平台的移植

  • SharpICTCLAS分词系统简介(1)读取词典库

    SharpICTCLAS分词系统简...

  • ICTCLAS(五)

    ICTCLAS(五)

  • ICTCLAS(六)

    ICTCLAS(六)