Archive for the ‘中文分词’ Category

Zend Framework — 中文分词 Analyzer

Tuesday, April 29th, 2008

最近在看Zend_Lucene_Search.查阅了一些资料. 这篇文章写的不错, 推荐一下.估计已经有很多人看过了.但是,其中的例子有点小问题, 需要修改一下才能跑起来, 我这里简单修改了一下, 放到附件中, 供以后需要的朋友下载 analyzer code.

附录代码(请不要直接使用, 请下载上面的zip中的code使用):

require_once 'Zend/Search/Lucene/Analysis/Analyzer.php'; 

class Simple_Chinese_Analyzer extends Zend_Search_Lucene_Analysis_Analyzer_Common
{

private $_position;

private $_cnStopWords = array();

public function setCnStopWords($cnStopWords){
$this->_cnStopWords = $cnStopWords;
}

public function reset()
{
$this->_position = 0;
$search = array(
",", "/", "\\", ".", ";", ":", "\"", "!", "~", "`", "^",
"(", ")", "?", "-", "t", "n", "'", "<", ">", "\r", "\r\n",
"$", "&", "%", "#", "@", "+", "=", "{", "}", "[", "]", ":",
")", "(", ".", "。", ",", "!", ";", "“", "”", "‘", "’",
"[", "]", "、", "—", " ", "《", "》", "-", "…", "【", "】");
$this->_input = str_replace($search,' ',$this->_input);
$this->_input = str_replace($this->_cnStopWords,' ',$this->_input);
}

public function nextToken()
{
if ($this->_input === null) {
return null;
}
while ($this->_position < strlen($this->_input)) {
while ($this->_position < strlen($this->_input) &&
$this->_input[$this->_position]==' ' ) {
$this->_position++;
}
$termStartPosition = $this->_position;
$temp_char = $this->_input[$this->_position];
$isCnWord = false;
if(ord($temp_char)>127){
$i = 0;
while ($this->_position < strlen($this->_input) &&
ord( $this->_input[$this->_position] )>127) {
$this->_position = $this->_position + 3;
$i ++;
if($i==2){
$isCnWord = true;
break;
}
}
if($i==1)continue;
}else{
while ($this->_position < strlen($this->_input) &&
ctype_alnum( $this->_input[$this->_position] )) {
$this->_position++;
}
}
if ($this->_position == $termStartPosition) {
return null;
}

$token = new Zend_Search_Lucene_Analysis_Token(
substr($this->_input,
$termStartPosition,
$this->_position - $termStartPosition),
$termStartPosition,
$this->_position);
$token = $this->normalize($token);
if($isCnWord)$this->_position = $this->_position - 3;
if ($token !== null) {
return $token;
}
}
return null;
}

}

$stopWords = array('a', 'an', 'at', 'the', 'and', 'or', 'is', 'am');

$stopWordsFilter = new Zend_Search_Lucene_Analysis_TokenFilter_StopWords($stopWords);
$analyzer = new Simple_Chinese_Analyzer();
$cnStopWords = array('的');
$analyzer->setCnStopWords($cnStopWords);
$analyzer->addFilter($stopWordsFilter);
$value = 'this is  (a test)【中文】的测试, 长春市长春药店';
$analyzer->setInput($value, 'utf-8');

$position     = 0;
$tokenCounter = 0;
while (($token = $analyzer->nextToken()) !== null)
{
$tokenCounter++;
$tokens[] = $token;
}
print_r($tokens);

?>

常用的分词算法 — 简介

Wednesday, March 26th, 2008


基于字符串匹配的分词方法, 这种方法又叫做机械分词方法, 包括如下:

  • 最大匹配法(Forward Maximum Matching method, FMM法):选取包含6-8个汉字的符号串作为最大符号串,把最大符号串与词典中的单词条目相匹配,如果不能匹配,就削掉一个汉字继续匹配,直到在词典中 找到相应的单词为止。匹配的方向是从右向左。
  • 逆向最大匹配法(Backward Maximum Matching method, BMM法):匹配方向与MM法相反,是从左向右。实验表明:对于汉语来说,逆向最大匹配法比最大匹配法更有效。
  • 双向匹配法(Bi-direction Matching method, BM法):比较MM法与RMM法的切分结果,从而决定正确的切分。
  • 最佳匹配法(Optimum Matching method, OM法):将词典中的单词按它们在文本中的出现频度的大小排列,高频度的单词排在前,频度低的单词排在后,从而提高匹配的速度。’
  • 最少分词法: 利用字典, 使每一句中切出的词数最小,可以和他方法组合使用.

基于理解的分词方法,

  • 这种分词方法是通过让计算机模拟人对句子的理解,达到识别词的效果,有点人工智能的意思. 其基本思想就是在分词的同时进行句法、语义分析,利用句法信息和语义信息来处理歧义现象。它通常包括三个部分:分词子系统、句法语义子系统、总控部分。在 总控部分的协调下,分词子系统可以获得有关词、句子等的句法和语义信息来对分词歧义进行判断,即它模拟了人对句子的理解过程。这种分词方法需要使用大量的 语言知识和信息。由于汉语语言知识的笼统、复杂性,难以将各种语言信息组织成机器可直接读取的形式,因此目前基于理解的分词系统还处在试验阶段。

基于统计的分词方法

  • 从形式上看,词是稳定的字的组合,因此在上下文中,相邻的字同时出现的次数越多,就越有可能构成一个词。因此字与字相邻共现的频率或概率能够较好的反映成 词的可信度。可以对语料中相邻共现的各个字的组合的频度进行统计,计算它们的互现信息。定义两个字的互现信息,计算两个汉字X、Y的相邻共现概率。互现信 息体现了汉字之间结合关系的紧密程度。当紧密程度高于某一个阈值时,便可认为此字组可能构成了一个词。这种方法只需对语料中的字组频度进行统计,不需要切 分词典,因而又叫做无词典分词法或统计取词方法。但这种方法也有一定的局限性,会经常抽出一些共现频度高、但并不是词的常用字组,例如“这一”、“之 一”、“有的”、“我的”、“许多的”等,并且对常用词的识别精度差,时空开销大。实际应用的统计分词系统都要使用一部基本的分词词典(常用词词典)进行 串匹配分词,同时使用统计方法识别一些新的词,即将串频统计和串匹配结合起来,既发挥匹配分词切分速度快、效率高的特点,又利用了无词典分词结合上下文识 别生词、自动消除歧义的优点。