您当前的位置: 首页 > 网站编程 > PHP教程 > php简易中文分词

php简易中文分词

作者:不详 来源:网络 发布时间: 2014-07-15 22:30 点击:
用PHP去做中文分词并不是一个太明智的举动, :p 下面是我根据网上找的一个字典档, 简易实现的一个分词程序. (注: 字典档是gdbm格式, key是词 value是词频, 约4万个常用词) 代码请参见http://www.shi8.com/out/support/art_316.txt ?php //中文分词系统简易实现办法 //切

php简易中文分词

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

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

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

  代码请参见http://www.shi8.com/out/support/art_316.txt
<?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>

  
分享到:
本文"php简易中文分词"由远航站长收集整理而来,仅供大家学习与参考使用。更多网站制作教程尽在远航站长站。
顶一下
(0)
0%
踩一下
(0)
0%
[点击 次] [返回上一页] [打印]
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 密码: 验证码:
关于本站 - 联系我们 - 网站声明 - 友情连接- 网站地图 - 站点地图 - 返回顶部
Copyright © 2007-2013 www.yhzhan.com(远航站长). All Rights Reserved .
远航站长:为中小站长提供最佳的学习与交流平台,提供网页制作与网站编程等各类网站制作教程.
官方QQ:445490277 网站群:26680406 网站备案号:豫ICP备07500620号-4