本文目录导读:

我来为您提供一个完整的PHP敏感词DFA(确定性有限自动机)算法实现:
基础DFA类实现
<?php
class SensitiveWordFilter
{
private $dict = [];
private $replaceChar = '*';
/**
* 添加敏感词到DFA树
* @param string $word 敏感词
*/
public function addWord($word)
{
$word = trim($word);
if (empty($word)) {
return;
}
$len = mb_strlen($word, 'UTF-8');
$tree = &$this->dict;
for ($i = 0; $i < $len; $i++) {
$char = mb_substr($word, $i, 1, 'UTF-8');
if (!isset($tree[$char])) {
$tree[$char] = [];
}
$tree = &$tree[$char];
}
// 标记为敏感词结束
$tree['end'] = true;
}
/**
* 批量添加敏感词
* @param array $words 敏感词数组
*/
public function addWords(array $words)
{
foreach ($words as $word) {
$this->addWord($word);
}
}
/**
* 检查文本中是否包含敏感词
* @param string $text 待检查文本
* @return array 返回找到的敏感词数组
*/
public function check($text)
{
$foundWords = [];
$textLen = mb_strlen($text, 'UTF-8');
for ($i = 0; $i < $textLen; $i++) {
$tree = $this->dict;
$word = '';
$continueFlag = false;
for ($j = $i; $j < $textLen; $j++) {
$char = mb_substr($text, $j, 1, 'UTF-8');
// 过滤空白字符(可选)
if (trim($char) === '' && $continueFlag) {
$continueFlag = false;
continue;
}
if (!isset($tree[$char])) {
break;
}
$word .= $char;
$tree = $tree[$char];
if (isset($tree['end']) && $tree['end']) {
$foundWords[] = $word;
// 可选:跳过后续字符
$i = $j;
}
$continueFlag = true;
}
}
return array_unique($foundWords);
}
/**
* 过滤敏感词
* @param string $text 待过滤文本
* @param string $replaceChar 替换字符
* @return array ['text' => 过滤后文本, 'found' => 找到的敏感词]
*/
public function filter($text, $replaceChar = '*')
{
$replaceCharArr = mb_str_split($replaceChar, 1, 'UTF-8');
$filteredText = $text;
$foundWords = [];
$textLen = mb_strlen($text, 'UTF-8');
$chars = mb_str_split($text, 1, 'UTF-8');
for ($i = 0; $i < $textLen; $i++) {
$tree = $this->dict;
$word = '';
$lastMatchPos = -1;
$lastMatchLen = 0;
for ($j = $i; $j < $textLen; $j++) {
if (!isset($chars[$j])) {
break;
}
$char = $chars[$j];
if (!isset($tree[$char])) {
break;
}
$word .= $char;
$tree = $tree[$char];
if (isset($tree['end']) && $tree['end']) {
$lastMatchPos = $j;
$lastMatchLen = strlen($word);
}
}
if ($lastMatchPos >= 0 && $lastMatchLen > 0) {
// 找到敏感词
$sensitiveWord = mb_substr($text, $i, $lastMatchLen, 'UTF-8');
$foundWords[] = $sensitiveWord;
// 替换敏感词
$replaceStr = str_repeat($replaceChar, mb_strlen($sensitiveWord, 'UTF-8'));
$filteredText = mb_substr($filteredText, 0, $i, 'UTF-8')
. $replaceStr
. mb_substr($filteredText, $i + $lastMatchLen, null, 'UTF-8');
// 跳过已处理的字符
$i = $lastMatchPos;
}
}
return [
'text' => $filteredText,
'found' => array_unique($foundWords)
];
}
/**
* 获取DFA树结构(用于调试)
*/
public function getDict()
{
return $this->dict;
}
/**
* 清空词典
*/
public function clear()
{
$this->dict = [];
}
}
// 辅助函数:将字符串拆分为字符数组
if (!function_exists('mb_str_split')) {
function mb_str_split($string, $split_length = 1, $encoding = null)
{
if ($split_length <= 0) {
return [];
}
$encoding = $encoding ?: mb_internal_encoding();
$result = [];
$strLength = mb_strlen($string, $encoding);
for ($i = 0; $i < $strLength; $i += $split_length) {
$result[] = mb_substr($string, $i, $split_length, $encoding);
}
return $result;
}
}
使用示例
// 创建实例
$filter = new SensitiveWordFilter();
// 添加敏感词
$filter->addWord('赌博');
$filter->addWord('毒品');
$filter->addWord('色情');
$filter->addWord('暴力');
// 或者批量添加
$filter->addWords(['赌博', '毒品', '色情', '暴力', '违法', '犯罪']);
// 从文件加载敏感词
function loadWordsFromFile($filter, $filePath)
{
$words = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$filter->addWords($words);
}
// 检查文本
$text = "这是一个包含赌博和毒品的例子,还有色情内容";
$found = $filter->check($text);
print_r($found);
// 输出: Array ( [0] => 赌博 [1] => 毒品 [2] => 色情 )
// 过滤敏感词
$result = $filter->filter("这是一个包含赌博和毒品的例子,还有色情内容", '*');
echo $result['text']; // 这是一个包含**和**的例子,还有**内容
print_r($result['found']); // Array ( [0] => 赌博 [1] => 毒品 [2] => 色情 )
高级版本(支持更多特性)
<?php
class AdvancedSensitiveWordFilter extends SensitiveWordFilter
{
private $skipChars = [' ', ' ', '\t', '\n', '@', '#', '$', '%', '^', '&', '*', '-', '_', '+', '='];
private $enableSkipChar = true;
private $enablePinyinMatch = false;
/**
* 设置是否启用跳过字符
*/
public function setSkipCharEnabled($enabled)
{
$this->enableSkipChar = $enabled;
}
/**
* 添加自定义跳过字符
*/
public function addSkipChar($char)
{
$this->skipChars[] = $char;
}
/**
* 改进的检查方法,支持跳过字符
*/
public function check($text)
{
$foundWords = [];
$textLen = mb_strlen($text, 'UTF-8');
$chars = mb_str_split($text, 1, 'UTF-8');
for ($i = 0; $i < $textLen; $i++) {
$tree = $this->dict;
$word = '';
$skipCount = 0;
for ($j = $i; $j < $textLen; $j++) {
$char = $chars[$j];
// 跳过字符处理
if ($this->enableSkipChar && in_array($char, $this->skipChars)) {
$skipCount++;
if ($skipCount > 3) { // 最多跳过3个字符
break;
}
continue;
}
if (!isset($tree[$char])) {
break;
}
$word .= $char;
$tree = $tree[$char];
if (isset($tree['end']) && $tree['end']) {
$foundWords[] = $word;
}
}
}
return array_unique($foundWords);
}
/**
* 从JSON文件加载敏感词
*/
public function loadFromJson($jsonPath)
{
if (!file_exists($jsonPath)) {
throw new Exception("File not found: $jsonPath");
}
$data = json_decode(file_get_contents($jsonPath), true);
if (isset($data['words'])) {
$this->addWords($data['words']);
}
}
/**
* 导出词典为JSON(可用于保存)
*/
public function exportToJson()
{
return json_encode(['words' => $this->getAllWords()], JSON_UNESCAPED_UNICODE);
}
/**
* 获取所有敏感词(需要遍历DFA树)
*/
public function getAllWords()
{
$words = [];
$this->traverseDict($this->dict, '', $words);
return $words;
}
/**
* 递归遍历DFA树获取所有敏感词
*/
private function traverseDict($node, $prefix, &$words)
{
foreach ($node as $char => $subTree) {
if ($char === 'end') {
$words[] = $prefix;
continue;
}
$this->traverseDict($subTree, $prefix . $char, $words);
}
}
/**
* 智能过滤(支持上下文感知)
*/
public function smartFilter($text)
{
$result = $this->filter($text, '*');
// 可以在这里添加更多智能处理逻辑
// 保留首尾字符、部分替换等
return $result;
}
}
性能优化版本
<?php
class HighPerformanceSensitiveWordFilter
{
private $dict = [];
private $cache = [];
private $cacheSize = 1000;
/**
* 使用数组引用进行更高效的操作
*/
public function addUserDict($word)
{
$charCount = mb_strlen($word, 'UTF-8');
$p = &$this->dict;
for ($i = 0; $i < $charCount; $i++) {
$char = mb_substr($word, $i, 1, 'UTF-8');
if (!isset($p[$char])) {
$p[$char] = [];
}
$p = &$p[$char];
}
if (!isset($p['end'])) {
$p['end'] = true;
}
}
/**
* 带缓存的高性能过滤
*/
public function filterWithCache($text)
{
// 检查缓存
if (isset($this->cache[$text])) {
return $this->cache[$text];
}
$result = $this->filter($text, '*');
// 管理缓存大小
if (count($this->cache) >= $this->cacheSize) {
array_shift($this->cache);
}
$this->cache[$text] = $result;
return $result;
}
/**
* 高效过滤方法(避免mb_substr重复调用)
*/
public function fastFilter($text, $replaceChar = '*')
{
$textLen = mb_strlen($text, 'UTF-8');
if ($textLen === 0) {
return ['text' => $text, 'found' => []];
}
$chars = mb_str_split($text, 1, 'UTF-8');
$result = '';
$found = [];
$i = 0;
while ($i < $textLen) {
$tree = $this->dict;
$matched = false;
$j = $i;
while ($j < $textLen) {
$char = $chars[$j];
if (!isset($tree[$char])) {
break;
}
$tree = $tree[$char];
$j++;
if (isset($tree['end'])) {
$word = implode('', array_slice($chars, $i, $j - $i));
$found[] = $word;
$result .= str_repeat($replaceChar, $j - $i);
$i = $j;
$matched = true;
break;
}
}
if (!$matched) {
$result .= $chars[$i];
$i++;
}
}
return [
'text' => $result,
'found' => array_unique($found)
];
}
}
使用建议
// 使用示例
$filter = new AdvancedSensitiveWordFilter();
// 加载敏感词库
$filter->addWords([
'赌博', '毒品', '色情', '暴力',
'诈骗', '传销', '赌博网址', '代购毒品'
]);
// 测试过滤
$text = "这是一个包含赌博和毒品的内容,还有赌博网址";
$result = $filter->smartFilter($text);
echo $result['text']; // 输出过滤后的文本
print_r($result['found']); // 输出找到的敏感词
// 批量处理
$texts = [
'文本1包含赌博',
'文本2正常内容',
'文本3包含毒品和色情'
];
foreach ($texts as $text) {
$result = $filter->filterWithCache($text);
echo $result['text'] . "\n";
}
关键特性:
- 高效匹配:DFA算法时间复杂度为O(n),n为文本长度
- 内存优化:使用数组结构,共享前缀路径
- 支持中文:正确处理UTF-8编码
- 可扩展性:支持添加自定义逻辑(如跳过字符、拼音匹配等)
这个实现包含了基础DFA、高级特性和性能优化版本,可以根据实际需求选择合适的版本使用。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播