[转]用PHP简易实现中文分词

用PHP简易实现中文分词


文章作者:Hightman
文章来自:http://php.twomice.net/show_hdr.php?xname=BORRG11&dname=P7SRG11&xpos=7


hehe, 用PHP去做中文分词并不是一个太明智的举动, :p

下面是我根据网上找的一个字典档, 简易实现的一个分词程序.

(注: 字典档是gdbm格式, key是词 value是词频, 约4万个常用词)

完整的程序演示及下载请参见: http://root.twomice.net/my_php4/dict/chinese_segment.php

<?php
//中文分词系统简易实现办法
//切句单位:凡是ascii值<128的字符
//常见双字节符号:《》,。、?“”;:!¥…… %$#@^&*()[]{}|\/"'
//可以考虑加入超常见中文字:的和是不了啊(不过有特殊字比如"打的""郑和"..:p)

//计算时间
functiongetmicrotime(){
list($usec,$sec)=explode("",microtime());
return((float)$usec+(float)$sec);
}
$time_start=getmicrotime();


//词典类
classch_dictionary{
var$_id;

functionch_dictionary($fname=""){
if($fname!=""){
$this->load($fname);
}
}

//根据文件名载入字典(gdbm数据档案)
functionload($fname){
$this->_id=dba_popen($fname,"r","gdbm");
if(!$this->_id){
echo"failedtoopenthedictionary.($fname)<br>/n";
exit;
}
}

//根据词语返回频率,不存在返回-1
functionfind($word){
$freq=dba_fetch($word,$this->_id);
if(is_bool($freq))$freq=-1;
return$freq;
}
}

//分词类:(逆向)
//先将输入的字串正向切成句子,然后一句一句的分词,返回由词组成的数组.
classch_word_split{
var$_mb_mark_list;//常见切分句子的全角标点
var$_word_maxlen;//单个词最大可能长度(汉字字数)
var$_dic;//词典...
var$_ignore_mark;//trueorfalse

functionch_word_split(){
$this->_mb_mark_list=array(","," ","。","!","?",":","……","、","“","”","《","》","(",")");
$this->_word_maxlen=12;//12个汉字
$this->_dic=NULL;
$this->_ignore_mark=true;
}

//设定字典
functionset_dic($fname){
$this->_dic=newch_dictionary($fname);
}

functionset_ignore_mark($set){
if(is_bool($set))$this->_ignore_mark=$set;
}

//将字串切成句子再加以切分成词
functionstring_split($str,$func=""){
$ret=array();

if($func==""||!function_exists($func))$func="";

$len=strlen($str);
$qtr="";

for($i=0;$i<$len;$i++){
$char=$str[$i];

if(ord($char)<0xa1){
//读取到一个半角字符
if(!empty($qtr)){
$tmp=$this->_sen_split($qtr);
$qtr="";

if($func!="")call_user_func($func,$tmp);
else$ret=array_merge($ret,$tmp);
}

//如果是单词或数字.根据char将数据读取到>=0xa1为止
if($this->_is_alnum($char)){
do{
if(($i+1)>=$len)break;
$char2=substr($str,$i+1,1);
if(!$this->_is_alnum($char2))break;

$char.=$char2;
$i++;
}while(1);

if($func!="")call_user_func($func,array($char));
else$ret[]=$char;
}
elseif($char==''||$char=="/t"){
//nothing.
continue;
}
elseif(!$this->_ignore_mark){
if($func!="")call_user_func($func,array($char));
else$ret[]=$char;
}
}
else{
//双字节字符.
$i++;
$char.=$str[$i];

if(in_array($char,$this->_mb_mark_list)){
if(!empty($qtr)){
$tmp=$this->_sen_split($qtr);
$qtr="";

if($func!="")call_user_func($func,$tmp);
else$ret=array_merge($ret,$tmp);
}

if(!$this->_ignore_mark){
if($func!="")call_user_func($func,array($char));
else$ret[]=$char;
}
}
else{
$qtr.=$char;
}
}
}

if(strlen($qtr)>0){
$tmp=$this->_sen_split($qtr);

if($func!="")call_user_func($func,$tmp);
else$ret=array_merge($ret,$tmp);
}

//returnvalue
if($func==""){
return$ret;
}
else{
returntrue;
}
}

//将句子切成词,逆向
function_sen_split($sen){
$len=strlen($sen)/2;
$ret=array();

for($i=$len-1;$i>=0;$i--){
//如:这是一个分词程序

//先取得最后一个字
$w=substr($sen,$i*2,2);

//最终的词长
$wlen=1;

//开始逆向匹配到最大长度.
$lf=0;//lastfreq
for($j=1;$j<=$this->_word_maxlen;$j++){
$o=$i-$j;
if($o<0)break;
$w2=substr($sen,$o*2,($j+1)*2);

$tmp_f=$this->_dic->find($w2);
//echo"{$i}.{$j}:$w2(f:$tmp_f)/n";
if($tmp_f>$lf){
$lf=$tmp_f;
$wlen=$j+1;
$w=$w2;
}
}
//根据$wlen将$i偏移了
$i=$i-$wlen+1;
array_push($ret,$w);
}

$ret=array_reverse($ret);
return$ret;
}

//判断字符是不是字母数字_-[0-9a-z_-]
function_is_alnum($char){
$ord=ord($char);
if($ord==45||$ord==95||($ord>=48&&$ord<=57))
returntrue;
if(($ord>=97&&$ord<=122)||($ord>=65&&$ord<=90))
returntrue;
returnfalse;
}
}


//分词后的回调函数
functioncall_back($ar){
foreach($aras$tmp){
echo$tmp."";
//flush();
}
}

//实例(如果没有输入就从sample.txt中读取):
$wp=newch_word_split();
$wp->set_dic("dic.db");

if(!isset($_REQUEST['testdat'])||empty($_REQUEST['testdat'])){
$data=file_get_contents("sample.txt");
}
else{
$data=&$_REQUEST['testdat'];
}

//output
echo"<h3>简易分词演示</h3>/n";
echo"<hr>/n";
echo"分词结果(".strlen($data)."chars):<br>/n<textareacols=100rows=10>/n";

//设定是否忽略不返回分词符号(标点,常用字)
$wp->set_ignore_mark(false);

//执行切分,如果没有设置callback函数,则返回由词组成的array
$wp->string_split($data,"call_back");

$time_end=getmicrotime();
$time=$time_end-$time_start;

echo"</textarea><br>/n本次分词耗时:$timeseconds<br>/n";
?>
<hr>
<formmethod=post>
您也可以在下面文本框中输入文字,提交后试验分词效果:<br>
<textareaname=testdatcols=100rows=10></textarea><br>
<inputtype=submit>
</form>
<hr>
附:<br>
<li>本程序源码:<ahref="chinese_segment.phps">chinese_segment.php</a>(简易实现方式)</li>
<li>需要的字典:<ahref="dic.db">dic.db</a>(gdbm格式)</li>


附:
(简易中文分词实现完整代码及字典下载)
http://php.twomice.net/show_hdr.php?xname=BORRG11&dname=P7SRG11&xpos=19
(C版简易中文分词服务程序(cscwsd))
http://php.twomice.net/show_hdr.php?xname=BORRG11&dname=P7SRG11&xpos=40

你可能感兴趣的:(中文分词)