PHP中文分词的简单实现代码分享
程序员文章站
2022-11-27 16:03:08
当然, 本文不是要对中文搜索引擎做研究, 而是分享如果用 php 做一个站内搜索引擎。 本文是这个系统中的一篇。 我使用的分词工具是中科院计算所的开源版本的 ictclas...
当然, 本文不是要对中文搜索引擎做研究, 而是分享如果用 php 做一个站内搜索引擎。 本文是这个系统中的一篇。
我使用的分词工具是中科院计算所的开源版本的 ictclas。 另外还有开源的 bamboo, 我随后也会对该工具进行调研。
从 ictclas 出发是个不错的选择, 因为其算法传播比较广泛, 有公开的学术文档, 并且编译简单, 库依赖少。 但目前只提供了 c/c++, java 和 c# 版本的代码, 并没有 php 版本的代码。 怎么办呢? 也许可以学习它的 c/c++ 源码和学术文档中, 然后再开发一个 php 版本出来。 不过, 我要使用进程间通信, 在 php 代码里调用 c/c++ 版本的可执行文件。
下载源码解压后, 在有 c++ 开发库和编译环境的机器上直接 make ictclas 即可。 它的 makefile 脚本有个错误, 执行测试的代码没有加上'。/', 当然不能像 windows 下执行成功了。 但也不影响编译结果。
进行中文分词的 php 类就在下面了, 用 proc_open() 函数来执行分词程序, 并通过管道和其交互, 输入要进行分词的文本, 读取分词结果。
<?php
class nlp{
private static $cmd_path;
// 不以'/'结尾
static function set_cmd_path($path){
self::$cmd_path = $path;
}
private function cmd($str){
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
);
$cmd = self::$cmd_path . "/ictclas";
$process = proc_open($cmd, $descriptorspec, $pipes);
if (is_resource($process)) {
$str = iconv('utf-8', 'gbk', $str);
fwrite($pipes[0], $str);
$output = stream_get_contents($pipes[1]);
fclose($pipes[0]);
fclose($pipes[1]);
$return_value = proc_close($process);
}
/*
$cmd = "printf '$input' | " . self::$cmd_path . "/ictclas";
exec($cmd, $output, $ret);
$output = join("\n", $output);
*/
$output = trim($output);
$output = iconv('gbk', 'utf-8', $output);
return $output;
}
/**
* 进行分词, 返回词语列表.
*/
function tokenize($str){
$tokens = array();
$output = self::cmd($input);
if($output){
$ps = preg_split('/\s+/', $output);
foreach($ps as $p){
list($seg, $tag) = explode('/', $p);
$item = array(
'seg' => $seg,
'tag' => $tag,
);
$tokens[] = $item;
}
}
return $tokens;
}
}
nlp::set_cmd_path(dirname(__file__));
?>
使用起来很简单(确保 ictclas 编译后的可执行文件和词典在当前目录):
<?php
require_once('nlp.php');
var_dump(nlp::tokenize('hello, world!'));
?>
我使用的分词工具是中科院计算所的开源版本的 ictclas。 另外还有开源的 bamboo, 我随后也会对该工具进行调研。
从 ictclas 出发是个不错的选择, 因为其算法传播比较广泛, 有公开的学术文档, 并且编译简单, 库依赖少。 但目前只提供了 c/c++, java 和 c# 版本的代码, 并没有 php 版本的代码。 怎么办呢? 也许可以学习它的 c/c++ 源码和学术文档中, 然后再开发一个 php 版本出来。 不过, 我要使用进程间通信, 在 php 代码里调用 c/c++ 版本的可执行文件。
下载源码解压后, 在有 c++ 开发库和编译环境的机器上直接 make ictclas 即可。 它的 makefile 脚本有个错误, 执行测试的代码没有加上'。/', 当然不能像 windows 下执行成功了。 但也不影响编译结果。
进行中文分词的 php 类就在下面了, 用 proc_open() 函数来执行分词程序, 并通过管道和其交互, 输入要进行分词的文本, 读取分词结果。
复制代码 代码如下:
<?php
class nlp{
private static $cmd_path;
// 不以'/'结尾
static function set_cmd_path($path){
self::$cmd_path = $path;
}
private function cmd($str){
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
);
$cmd = self::$cmd_path . "/ictclas";
$process = proc_open($cmd, $descriptorspec, $pipes);
if (is_resource($process)) {
$str = iconv('utf-8', 'gbk', $str);
fwrite($pipes[0], $str);
$output = stream_get_contents($pipes[1]);
fclose($pipes[0]);
fclose($pipes[1]);
$return_value = proc_close($process);
}
/*
$cmd = "printf '$input' | " . self::$cmd_path . "/ictclas";
exec($cmd, $output, $ret);
$output = join("\n", $output);
*/
$output = trim($output);
$output = iconv('gbk', 'utf-8', $output);
return $output;
}
/**
* 进行分词, 返回词语列表.
*/
function tokenize($str){
$tokens = array();
$output = self::cmd($input);
if($output){
$ps = preg_split('/\s+/', $output);
foreach($ps as $p){
list($seg, $tag) = explode('/', $p);
$item = array(
'seg' => $seg,
'tag' => $tag,
);
$tokens[] = $item;
}
}
return $tokens;
}
}
nlp::set_cmd_path(dirname(__file__));
?>
使用起来很简单(确保 ictclas 编译后的可执行文件和词典在当前目录):
复制代码 代码如下:
<?php
require_once('nlp.php');
var_dump(nlp::tokenize('hello, world!'));
?>
上一篇: PHP 验证码的实现代码