php实现BMM分词算法
BMM算法,逆向最大匹配法(backward maximum matching method, BMM),和FMM一样,都是基于词表的分词方法。
与FMM不同的是,BMM是对于一段文本从右至左进行扫描,利用词典里面的词汇切分出长度最长的词,也就是说文本扫描的方式刚好与FMM相反。分词效果相对FMM来说,BMM算法更好。
以下是简单实现
<?php
class BMM
{
//简单定义一个词典数组
private $dict = [];
private $result = []; //结果集
// 是否为词典中的词
private function inDict($str)
{
$flag = false;
//遍历整个词典
for ($i = 0; $i < count($this->dict); $i++) {
// 是否有词典相等的词
if ($str == $this->dict[$i]) {
$flag = true;
break;
}
}
return $flag;
}
public function loadDict(array $array)
{
$this->dict = $array;
}
/**
* @param $sentence 要匹配的句子
* @param $matchWordLength 匹配词组的最大长度
* 要确认这个值要大于等于你字典长度最长词的长度
* 超过这个长度的词无法正确匹配
*/
public function split($sentence, $matchWordLength = 6)
{
$this->result = []; //重置结果集
$sentenceLength = mb_strlen($sentence); //计算句子长度
for ($i = 0; $i < $sentenceLength;) {
//计算截取词的长度
if ($sentenceLength - $i < $matchWordLength) {
$matchWordLength = $sentenceLength - $i;
}
//计算截取字符串的偏移量
$strBegin = $sentenceLength - $i - $matchWordLength;
// 截取的要处理的子句子
$subSentence = mb_substr($sentence, $strBegin, $matchWordLength);
//拆分子句子的词
for ($j = 0; $j < $matchWordLength; $j++) {
$k = $matchWordLength - $j;
//切出词
$tmp = mb_substr($subSentence, $j, $k);
//如果词典有该词或者是单词
if ($this->inDict($tmp) || $j == $matchWordLength - 1) {
$this->result[] = $tmp;
$i = $i + $k; //修改偏移量
break;
}
}
}
//因为切换是从右至左,所以倒序一下
krsort($this->result);
}
public function getResultText()
{
return implode(" \ ", $this->result);
}
}
使用方式
$BMM = new BMM();
$BMM->loadDict(['的确', '王公', '实在', '在理', '公子', '确实']);
$BMM->split('王公子说的确实在理');
echo $BMM->getResultText() . "\n";
实际效果
王 公子 说 的 确实 在理
实际效果会比FMM效果好些
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
评论已关闭