1.DFA算法简介

DFA全称为:Deterministic Finite Automaton,即确定有穷自动机。其特征为:有一个有限状态集合和一些从一个状态通向另一个状态的边,每条边上标记有一个符号,其中一个状态是初态,某些状态是终态。但不同于不确定的有限自动机,DFA中不会有从同一状态出发的两条边标志有相同的符号。

<?php
/**
* 敏感词过滤方法.
*/ namespace app\common\tool; use app\common\model\Sensitive; class SensitiveTool
{
private static $arrHashMap = [];
private static $file = ROOT_PATH.'runtime'.DS.'sensitive.txt'; /**
* 把敏感词保存为文件
* @return bool|int
*/
public static function saveSensitiveWord(){
$data = Sensitive::all();
foreach( $data as $k => $v ){
self::addKeyWord($v['name']);
}
return file_put_contents(self::$file,serialize(self::$arrHashMap)); } /**
* 过滤敏感词
* @param $strWord
* @return mixed
*/
public static function filterSensitiveWord( $strWord ){
$file = unserialize(file_get_contents(self::$file));
$resStr = $strWord;
if(!empty($file)){
$len = mb_strlen($strWord, 'UTF-8');
$arrHashMap = self::$arrHashMap = $file;
$newWord = '';
for ($i=0; $i < $len; $i++) {
$word = mb_substr($strWord, $i, 1, 'UTF-8');
if (!isset($arrHashMap[$word])) {
$arrHashMap = self::$arrHashMap;
$newWord = '';
}
$newWord .= $word;
if ($arrHashMap[$word]['end']) {
$asterisk = self::getAsterisk(mb_strlen($newWord, 'UTF-8'));
$resStr = str_replace($newWord,$asterisk,$resStr);
$newWord = '';
$arrHashMap = self::$arrHashMap;
} else{
$arrHashMap = $arrHashMap[$word]; }
}
} return $resStr;
} /**
* 过滤邮箱和手机号(8位以上数字)
* @param $msg
* @return string
*/
public static function filterTelMail( $msg ):string {
if(is_string((string)$msg)){
$msg = preg_replace('/\d{8,}/', '****', $msg);
$msg = preg_replace('/[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})/i', '****', $msg);
}else{
$msg = '';
} return $msg;
}
/**
* 新增敏感词的核心方法
* @param $strWord
*/
private static function addKeyWord( $strWord ) { //免定金峨眉牌汽枪
$len = mb_strlen($strWord, 'UTF-8'); $arrHashMap = &self::$arrHashMap;
for ($i=0; $i < $len; $i++) {
$word = mb_substr($strWord, $i, 1, 'UTF-8');
// 已存在
if (isset($arrHashMap[$word])) {
if ($i == ($len - 1)) {
$arrHashMap[$word]['end'] = 1;
}
} else {
// 不存在
if ($i == ($len - 1)) {
$arrHashMap[$word] = [];
$arrHashMap[$word]['end'] = 1;
} else {
$arrHashMap[$word] = [];
$arrHashMap[$word]['end'] = 0;
}
}
// 传址
$arrHashMap = &$arrHashMap[$word];
}
} /**
* 生成*号
* @param int $num
* @return string
*/
private static function getAsterisk( int $num ) :string {
$str = '';
for($i=1;$i<=$num;$i++) {
$str .= '*';
}
return $str;
} }

以下是网上优化思路,暂时没有考虑:

2.优化思路

2.1敏感词中间填充无意义字符问题

对于“王*八&&蛋”这样的词,中间填充了无意义的字符来混淆,在我们做敏感词搜索时,同样应该做一个无意义词的过滤,当循环到这类无意义的字符时进行跳过,避免干扰。

2.2敏感词用拼音或部分用拼音代替

两种解决思路:一种是最简单是遇到这类问题,先丰富敏感词库进行快速解决。第二种是判断时将敏感词转换为拼音进行对比判断。

不过目前这两种方案均不能彻底很好的解决该问题,此类问题还需进一步研究。

参考资源:

http://www.mamicode.com/info-detail-965728.html

https://blog.csdn.net/qq_36827957/article/details/74357283

05-11 11:30