1.DFA算法简介
DFA全称为:Deterministic Finite Automaton,即确定有穷自动机。其特征为:有一个有限状态集合和一些从一个状态通向另一个状态的边,每条边上标记有一个符号,其中一个状态是初态,某些状态是终态。但不同于不确定的有限自动机,DFA中不会有从同一状态出发的两条边标志有相同的符号。
<?php /** * 敏感词过滤方法. */ namespace appcommon ool; use appcommonmodelSensitive; 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