先介绍一下匹配敏感词原理吧,因为没有工具,画的很糙,有疑问直接联系我。(绿色箭头代表命中敏感词,灰色:未命中)
base 确定有穷自动机(DFA)算法
比如说“可以”是敏感词,那么遍历到“以”的时候直接终止遍历
比如说输入“可口”的时候,遍历到“口”的时候,这时候的文字状态是false,所以程序上认为“可口”并非是敏感词(在树上的每一个文字都有一个end状态,只有最后一个字的end=true,其他都是false)
实现步骤
首先将 lustre/php-dfa-sensitive composer下来
composer 官网地址:lustre/php-dfa-sensitive - Packagist
直接上代码,用个单例模式吧
<?php
/**
* @CreatedBy fanbin
*
* @CreatedTime 2021/12/28 17:59
*
* @Describe 敏感词汇过滤
*/
namespace App\Admin;
use App\Notice;
use Illuminate\Support\Facades\Redis;
use DfaFilter\SensitiveHelper;
class SensitiveWords
{
//当前类对象的属性
private static $instance;
/**
* 防止实例化
*/
private function __construct()
{
}
/**
* 防止克隆
*/
private function __clone()
{
}
/**
* 获取实例
*/
public static function getInstance()
{
if (!self::$instance instanceof self) {
self::$instance = SensitiveHelper::init();
$words = self::getSensitiveWords();
self::$instance->setTree($words);
}
return self::$instance;
}
/**
* 获取敏感词汇
* 优先从redis获取
*
* @return array
*/
public static function getSensitiveWords()
{
$words = Redis::get('sensitive_words');
$words = json_decode($words, true);
if (!$words) {
$words = Notice::ins()->getSensitiveWords([]);
$words = array_column($words, 'b_word');
Redis::set('sensitive_words', json_encode($words));
}
return $words;
}
}
调用:
$handle = SensitiveHelper::init()->setTree($wordData);
检测是否带有敏感词
$islegal = $handle->islegal($content);
敏感词过滤
// 敏感词替换为*为例(会替换为相同字符长度的*)
$filterContent = $handle->replace($content, '*', true);
// 或敏感词替换为***为例
$filterContent = $handle->replace($content, '***');
标记敏感词
$markedContent = $handle->mark($content, '<mark>', '</mark>');
获取文字中的敏感词
// 获取内容中所有的敏感词
$sensitiveWordGroup = $handle->getBadWord($content);
// 仅且获取一个敏感词
$sensitiveWordGroup = $handle->getBadWord($content, 1);
|