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