|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
我先解释一下我的学习思路。中文 hehe, 用PHP去做中文分词并非一个太明智的举措, :p
上面是我依据网上找的一个字典档, 简略单纯完成的一个分词法式.
(注: 字典档是gdbm格局, key是词 value是词频, 约4万个经常使用词)
完全的法式演示及下载请拜见: http://root.twomice.net/my_php4/dict/chinese_segment.php
<?php
//中文分词体系简略单纯完成举措
//切句单元:但凡ascii值<128的字符
//罕见双字节符号:《》,。、?“”;:!¥…… %$#@^&*()[]{}|\/"'
//可以思索到场超凡见中文字: 的 和 是 不 了 啊 (不外有特别字好比 "打的" "郑和" .. :p)
//盘算工夫
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$time_start = getmicrotime();
//辞书类
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)<br>\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 "<h3>简略单纯分词演示</h3>\n";
echo "<hr>\n";
echo "分词了局(" . strlen($data) . " chars): <br>\n<textarea cols=100 rows=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本次分词耗时: $time seconds <br>\n";
?>
<hr>
<form method=post>
您也能够鄙人面文本框中输出文字,提交后实验分词后果:<br>
<textarea name=testdat cols=100 rows=10></textarea><br>
<input type=submit>
</form>
<hr>
附: <br>
<li>本法式源码: <a href="chinese_segment.phps">chinese_segment.php</a> (简略单纯完成体例)</li>
<li>需求的字典: <a href="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
刚开始觉得自己对这些多少有些基础,很简单,但是看了老师那么熟练的进行网页布局的时候,突然之间发现,其实,我的基础并没有自己想像的那么好,自己设计的页面其实并不好看,就连表格的边框为1像素都不会弄。 |
|