php简易中文分词,用PHP简易实现中文分词

//词典类

class ch_dictionary {

var $_id;

function ch_dictionary($fname = "") {

if ($fname != "") {

$this->load($fname);

}

}

// 根据文件名载入字典 (gdbm数据档案)

function load($fname) {

$this->_id = dba_popen($fname, "r", "gdbm");

if (!$this->_id) {

echo "failed to open the dictionary.($fname)
\n";

exit;

}

}

// 根据词语返回频率, 不存在返回-1

function find($word) {

$freq = dba_fetch($word, $this->_id);

if (is_bool($freq)) $freq = -1;

return $freq;

}

}

// 分词类: (逆向)

// 先将输入的字串正向切成句子, 然后一句一句的分词, 返回由词组成的数组.

class ch_word_split {

var $_mb_mark_list;    // 常见切分句子的全角标点

var $_word_maxlen;    // 单个词最大可能长度(汉字字数)

var $_dic;        // 词典...

var $_ignore_mark;    // true or false

function ch_word_split () {

$this->_mb_mark_list = array(","," ","。","!","?",":","……","、","“","”","《","》","(",")");

$this->_word_maxlen  = 12;    // 12个汉字

$this->_dic = null;

$this->_ignore_mark = true;

}

// 设定字典

function set_dic($fname) {

$this->_dic = new ch_dictionary($fname);

}

function set_ignore_mark($set) {

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

}

// 将字串切成句子再加以切分成词

function string_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);

}

// return value

if ($func == "") {

return $ret;

}

else {

return true;

}

}

// 将句子切成词, 逆向

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; // last freq

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))

return true;

if (($ord >= 97 && $ord <= 122) || ($ord >= 65 && $ord <= 90))

return true;

return false;

}

}

// 分词后的回调函数

function call_back($ar) {

foreach ($ar as $tmp) {

echo $tmp . " ";

//flush();

}

}

// 实例(如果没有输入就从 sample.txt中读取):

$wp = new ch_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 "

简易分词演示

\n";

echo "


\n";

echo "分词结果(" . strlen($data) . " chars):
\n\n";

// 设定是否忽略不返回分词符号(标点,常用字)

$wp->set_ignore_mark(false);

// 执行切分, 如果没有设置 callback 函数, 则返回由词组成的array

$wp->string_split($data, "call_back");

$time_end = getmicrotime();

$time = $time_end - $time_start;

echo "
\n本次分词耗时: $time seconds
\n";

?>


您也可以在下面文本框中输入文字,提交后试验分词效果:


附:

本程序源码: chinese_segment.php (简易实现方式)需要的字典: dic.db (gdbm格式)

附:

(简易中文分词实现完整代码及字典下载)

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PHP中文分词代码使用居于unicode的词库,使用反向匹配模式分词,理论上兼容编码更广泛,并且对utf-8编码尤为方便。由于PhpanAlysis是无组件的系统,因此速度会比有组件的稍慢,不过在大量分词中,由于边分词边完成词库载入,因此内容越多,反而会觉得速度越快,这是正常现象,对于支持PHP-APC的服务器,本程序支持对词典进行缓存,这样做之后理论的速度并不慢于那些带组件的分词程序了。 分词系统是基于字符串匹配的分词方法 ,这种方法又叫做机械分词方法,它是按照一定的策略将待分析的汉字串与 一个“充分大的”机器词典中的词条进行配,若在词典中找到某个字符串,则匹配成功(识别出一个词)。按照扫描方向的不同,串匹配分词方法可以分为正向匹配 和逆向匹配;按照不同长度优先匹配的情况,可以分为最大(最长)匹配和最小(最短)匹配;按照是否与词性标注过程相结合,又可以分为单纯分词方法和分词与 标注相结合的一体化方法。常用的几种机械分词方法如下: 1)正向最大匹配法(由左到右的方向); 2)逆向最大匹配法(由右到左的方向); 3)最少切分(使每一句中切出的词数最小)。 还可以将上述各种方法相互组合,例如,可以将正向最大匹配方法和逆向最大匹配方法结合起来构成双向匹配法。由于汉语单字成词的特点,正向最小匹配和逆向 最小匹配一般很少使用。一般说来,逆向匹配的切分精度略高于正向匹配,遇到的歧义现象也较少。统计结果表明,单纯使用正向最大匹配的错误率为1/169, 单纯使用逆向最大匹配的错误率为1/245。但这种精度还远远不能满足实际的需要。实际使用的分词系统,都是把机械分词作为一种初分手段,还需通过利用各 种其它的语言信息来进一步提高切分的准确率。 一种方法是改进扫描方式,称为特征扫描或标志切分,优先在待分析字符串中识别和切分出一些带有明 显特征的词,以这些词作为断点,可将原字符串分为较小的串再来进机械分词,从而减少匹配的错误率。另一种方法是将分词和词类标注结合起来,利用丰富的词类 信息对分词决策提供帮助,并且在标注过程中又反过来对分词结果进行检验、调整,从而极大地提高切分的准确率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值