本文目录导读:

在 Laravel 中实现敏感词过滤,使用 Trie 树(前缀树)是非常合适且推荐的做法,尤其适合需要高效检测大量敏感词的场景。
为什么推荐 Trie 树?
优势
- 时间复杂度低:O(n) 级别的匹配速度,n 为文本长度
- 内存占用合理:共享前缀节点,适合大量敏感词
- 支持最长匹配:避免误判(如“共产党”和“共产党宣言”)
常见方案对比
| 方案 | 时间复杂度 | 内存占用 | 实现复杂度 |
|---|---|---|---|
| 正则表达式 | O(n*m) | 低 | 简单 |
| Trie树 | O(n) | 中等 | 中等 |
| Aho-Corasick | O(n) | 高 | 复杂 |
| 布隆过滤器 | O(n) | 低 | 需配合 |
Laravel 中实现 Trie 树敏感词过滤
安装包(推荐)
composer require sensortree/sensitive
use SensorTree\Sensitive;
$sensitive = new Sensitive();
$sensitive->addWords(['敏感词1', '敏感词2']);
$sensitive->filter('需要过滤的文本'); // 返回替换后的文本
自定义实现
namespace App\Services;
class TrieFilter
{
private $tree = [];
public function addWord($word)
{
$node = &$this->tree;
$len = mb_strlen($word);
for ($i = 0; $i < $len; $i++) {
$char = mb_substr($word, $i, 1);
if (!isset($node[$char])) {
$node[$char] = [];
}
$node = &$node[$char];
}
$node['end'] = true; // 标记结束
}
public function filter($text, $replace = '*')
{
$len = mb_strlen($text);
$result = '';
$positions = []; // 需要替换的字符位置
for ($i = 0; $i < $len; $i++) {
$node = $this->tree;
if (isset($node[mb_substr($text, $i, 1)])) {
$this->checkWord($text, $i, $node, $positions);
}
}
// 替换处理
for ($i = 0; $i < $len; $i++) {
$result .= isset($positions[$i]) ? $replace : mb_substr($text, $i, 1);
}
return $result;
}
private function checkWord($text, $start, $node, &$positions)
{
$len = mb_strlen($text);
for ($i = $start; $i < $len; $i++) {
$char = mb_substr($text, $i, 1);
if (!isset($node[$char])) break;
$node = $node[$char];
if (isset($node['end'])) {
// 标记要替换的字符
for ($j = $start; $j <= $i; $j++) {
$positions[$j] = true;
}
}
}
}
}
加载敏感词列表
class SensitiveService
{
protected $trie;
public function __construct()
{
$this->trie = new TrieFilter();
$words = config('sensitive.words'); // 从配置文件加载
foreach ($words as $word) {
$this->trie->addWord($word);
}
}
public function filter($text)
{
return $this->trie->filter($text);
}
}
在控制器中使用
use App\Services\SensitiveService;
class CommentController extends Controller
{
public function store(Request $request, SensitiveService $sensitive)
{
$content = $sensitive->filter($request->input('content'));
Comment::create([
'content' => $content,
'has_sensitive' => $content !== $request->input('content')
]);
return redirect()->back();
}
}
最佳实践建议
缓存 Trie 树
// 使用 Laravel 的缓存机制
Cache::rememberForever('sensitive_trie', function() {
$trie = new TrieFilter();
// 加载敏感词
return $trie;
});
分库存储敏感词
// 按等级分类
$sensitive->addWord('作弊', 1); // 1级:替换
$sensitive->addWord('赌博', 2); // 2级:直接拒绝
性能优化
- 使用
mb_*函数处理多字节字符 - 预编译 Trie 树,避免每次请求都重建
- 考虑使用 Swoole 扩展在内存中常驻
中文特殊处理
- 注意繁简体转换
- 支持拼音模糊匹配
- 处理好词语间的空格、符号
注意事项
- 内存占用:敏感词越多,Trie 树内存越大,建议控制在 10 万以内
- 并发安全:Trie 树是只读数据,不需要加锁
- 更新策略:支持热更新,但不建议频繁重建
- 误判处理:建议配合人工审核
如果对性能要求特别高(如实时聊天过滤),可以考虑使用 Aho-Corasick 算法,但实现复杂度会更高,对于大多数 Laravel 项目,Trie 树已经足够。