敏感词过滤的php代码,php实现敏感词过滤(Trie树)
靈感來自于 [嘉興ing](https://segmentfault.com/a/1190000019137933 "Trie樹 php 實現(xiàn)敏感詞過濾")
感謝分享.
本文主要是針對上文添加了自己的理解,以及增加了通過屏蔽等級靈活控制敏感詞過濾。
代碼適用場景:
1.特殊時間需要大規(guī)模針對某些敏感詞進(jìn)行敏感詞檢測
2.敏感詞除了精確匹配外還需要模糊匹配,如傻lkaj瓜
3.針對不同時期(例如重大節(jié)假日),或者是不同級別的項目,對敏感詞的校驗嚴(yán)格度不同,進(jìn)行進(jìn)一步處理。
實現(xiàn)邏輯
通過前綴樹/字典樹 算法,通過利用字符串的公共前綴來節(jié)約存儲空間。
例如當(dāng)前敏感詞數(shù)組為:['傻瓜','傻瓜蛋','傻子']
當(dāng)要匹配的字符串中含有 '傻瓜'、'傻子'時,下圖字典樹示例中的紅色邊框則為對應(yīng)的終止節(jié)點。
字典樹如圖所示:
首先需要通過敏感詞字典文件將敏感詞初始化字典樹,
然后在字典樹上搜索添加過的字符串。
其步驟如下:
1.從根結(jié)點開始搜索。
2.取得要查找字符串的第一個字符,根據(jù)該字符選擇對應(yīng)的字符路徑向下繼續(xù)搜索。
3.如果字符串搜索完成后,判斷當(dāng)前是否已經(jīng)是對應(yīng)敏感字符路徑的終止節(jié)點,如果是的話,說明字典樹中含有該字符串,反正說明不含有該字符串。
4.如果想要添加模糊匹配的話,可以在對應(yīng)字符路徑判斷的邏輯中,增加允許跳過的字符串長度判斷。
敏感詞等級處理
通過敏感詞校驗等級,來更靈活的控制屏蔽詞的力度。
一級屏蔽詞
校驗字符串中只要順序包含屏蔽詞,則都屏蔽。
如敏感詞:“傻瓜”,“你是不是傻啦吧唧瓜哪” -->“你是不是*啦吧唧*哪”
public function index()
{
$logic = new filterWords();
$str = $logic->filter('你是不是傻啦吧唧瓜哪',1);
echo '校驗結(jié)果:' . $str;
}
校驗結(jié)果:你是不是*啦吧唧*哪
二級屏蔽詞
校驗字符串中只要順序間隔n個字符內(nèi)包含屏蔽詞,則屏蔽。
如敏感詞:“傻瓜”,間隔2個字符內(nèi)屏蔽。
“你是不是傻啦吧瓜哪” -->“你是不是*啦吧*哪”
“你是不是傻啦吧唧瓜哪” -->“你是不是傻啦吧唧瓜哪”
public function index()
{
$logic = new filterWords();
$str = $logic->filter('你是不是傻啦吧瓜哪',2,2);
echo '校驗結(jié)果:' . $str;
}
校驗結(jié)果:你是不是*啦吧*哪
三級屏蔽詞
校驗字符串中只要全詞匹配屏蔽詞,則屏蔽。
如敏感詞:“傻瓜”。
“你是不是傻瓜哪” -->“你是不是**哪”
“你是不是傻啦吧唧瓜哪” -->“你是不是傻啦吧唧瓜哪”
public function index()
{
$logic = new filterWords();
$str = $logic->filter('你是不是傻瓜哪',3);
echo '校驗結(jié)果:' . $str;
}
校驗結(jié)果:你是不是**哪
思路流程圖:
封裝成一個工具類:filterWords.php
class filterWords
{
protected $dict;//敏感詞字典
public function __construct()
{
$this->loadDataFormFile();
}
/**
* 從文件中加載敏感詞字典
*/
protected function loadDataFormFile()
{
//此處可以修改為讀文件,一般敏感詞為文件形式,一行對應(yīng)一個敏感詞
//如果經(jīng)常調(diào)用的話,還可以通過緩存處理(redis、memcache)等等,此處不詳細(xì)處理
$arr = [
'笨蛋',
'傻瓜',
];
//將敏感詞加入此次節(jié)點
foreach ($arr as $value) {
$this->addWords(trim($value));
}
}
/**
* 分割文本
* @param $str
* @return array[]|false|string[]
*/
protected function splitStr($str)
{
//將字符串分割成組成它的字符
// 其中/u 表示按unicode(utf-8)匹配(主要針對多字節(jié)比如漢字),否則默認(rèn)按照ascii碼容易出現(xiàn)亂碼
return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
}
/**
* 添加敏感字至節(jié)點
* @param $words
*/
protected function addWords($words)
{
//1.分割字典
$wordArr = $this->splitStr($words);
$curNode = &$this->dict;
foreach ($wordArr as $char) {
if (!isset($curNode)) {
$curNode[$char] = [];
}
$curNode = &$curNode[$char];
}
//標(biāo)記到達(dá)當(dāng)前節(jié)點完整路徑為"敏感詞"
$curNode['end']++;
}
/**
* 敏感詞校驗
* @param $str ;需要校驗的字符串
* @param int $level ;屏蔽詞校驗等級 1-只要順序包含都屏蔽;2-中間間隔skipDistance個字符就屏蔽;3-全詞匹配即屏蔽
* @param int $skipDistance ;允許敏感詞跳過的最大距離,如笨aa蛋a傻瓜等等
* @param bool $isReplace ;是否需要替換,不需要的話,返回是否有敏感詞,否則返回被替換的字符串
* @param string $replace ;替換字符
* @return bool|string
*/
public function filter($str, $level = 1, $skipDistance = 2, $isReplace = true, $replace = '*')
{
//允許跳過的最大距離
if ($level == 1) {
$maxDistance = strlen($str) + 1;
} elseif ($level == 2) {
$maxDistance = max($skipDistance, 0) + 1;
} else {
$maxDistance = 2;
}
$strArr = $this->splitStr($str);
$strLength = count($strArr);
$isSensitive = false;
for ($i = 0; $i < $strLength; $i++) {
//判斷當(dāng)前敏感字是否有存在對應(yīng)節(jié)點
$curChar = $strArr[$i];
if (!isset($this->dict[$curChar])) {
continue;
}
$isSensitive = true; //引用匹配到的敏感詞節(jié)點
$curNode = &$this->dict[$curChar];
$dist = 0;
$matchIndex = [$i]; //匹配后續(xù)字符串是否match剩余敏感詞
for ($j = $i + 1; $j < $strLength && $dist < $maxDistance; $j++) {
if (!isset($curNode[$strArr[$j]])) {
$dist++; continue;
}
//如果匹配到的話,則把對應(yīng)的字符所在位置存儲起來,便于后續(xù)敏感詞替換
$matchIndex[] = $j;
//繼續(xù)引用
$curNode = &$curNode[$strArr[$j]];
}
//判斷是否已經(jīng)到敏感詞字典結(jié)尾,是的話,進(jìn)行敏感詞替換
if (isset($curNode['end']) && $isReplace) {
foreach ($matchIndex as $index) {
$strArr[$index] = $replace;
}
$i = max($matchIndex);
}
}
if ($isReplace) {
return implode('', $strArr);
} else {
return $isSensitive;
}
}
}
總結(jié)
以上是生活随笔為你收集整理的敏感词过滤的php代码,php实现敏感词过滤(Trie树)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iis php报错无法屏蔽,php屏蔽错
- 下一篇: php 函数 配置文件,php的几个配置