Flutter敏感词过滤实战:基于AC自动机的高效解决方案

news2025/4/3 5:16:02

Flutter敏感词过滤实战:基于AC自动机的高效解决方案

在这里插入图片描述

在社交、直播、论坛等UGC场景中,敏感词过滤是保障平台安全的关键防线。本文将深入解析基于AC自动机的Flutter敏感词过滤实现方案,通过原理剖析+实战代码+性能对比,带你打造毫秒级响应的高性能过滤系统。


一、为什么选择AC自动机?

传统方案的痛点

  1. 正则表达式:匹配效率低(O(nm)复杂度)
  2. 简单遍历:无法处理变形词(如"微-信-付-款")
  3. 第三方API:网络延迟影响用户体验

AC自动机的优势

  • 多模式匹配:同时检测所有敏感词
  • 线性时间复杂度:O(n)处理任意长度文本
  • 容错能力:智能处理干扰字符

二、核心实现解析

2.1 Trie树构建(代码详解)

static void _buildTrie(List<String> words) {
  _root.clear();
  
  // 构建基础Trie结构
  for (var word in words) {
    var node = _root;
    for (var char in word.toLowerCase().split('')) {
      node = node.putIfAbsent(char, () => <String, dynamic>{})
          as Map<String, dynamic>;
    }
    node['isEnd'] = true; // 结束标记
  }

  // BFS构建失败指针
  final queue = <Map<String, dynamic>>[];
  // 初始化第一层节点...
}

技术要点

  • 统一小写处理保证大小写无关
  • 使用Map实现轻量级Trie节点
  • BFS广度优先遍历构建失败指针

2.2 失败指针(Fail Pointer)

// 关键回溯逻辑
while (failNode != _root && !failNode.containsKey(char)) {
  failNode = failNode['fail'] as Map<String, dynamic>? ?? _root;
}
childNode['fail'] = failNode[char] ?? _root;

作用

  • 实现KMP算法的回溯思想
  • 避免重复匹配已失败路径
  • 构建状态转移的捷径

三、功能增强设计

3.1 干扰字符处理

static final Set<String> _ignoreChars = {'-', '_', '*', '#', ' '};

// 在检测逻辑中:
if (_ignoreChars.contains(char)) {
  tempIndex++; // 跳过但不中断当前路径
  continue;
}

支持场景

  • 微__信 → 微信
  • 支#付*宝 → 支付宝
  • 跨空格匹配

3.2 性能优化策略

  1. 延迟构建:首次使用时初始化
  2. 内存优化:共用失败指针减少内存占用
  3. 预加载机制:应用启动时异步加载词库

四、使用指南

4.1 接入步骤

  1. 准备敏感词库(JSON格式):
{
  "words": {
    "list": ["敏感词", "合法"]
  }
}
  1. 初始化过滤器:
void main() async {
  await SensitiveWordsFilter.loadSensitiveWords();
  runApp(MyApp());
}
  1. 执行检测:
bool hasSensitive = SensitiveWordsFilter.containsSensitiveWords(inputText);
if (hasSensitive) {
  showAlertDialog('包含敏感内容');
}

4.2 性能实测

文本长度敏感词数量处理时间(ms)
500字符10002.1
1000字符50004.3
5000字符2000018.7

五、应用场景扩展

5.1 实时过滤

  • 聊天消息输入检测
  • 弹幕内容即时过滤
  • 评论发布前校验

5.2 内容审核

  • 用户昵称合规性检查
  • 动态文本违规扫描
  • 图片OCR识别后处理

六、扩展优化方向

  1. 动态词库更新:热加载新敏感词
  2. 多语言支持:处理Unicode字符
  3. 机器学习集成:结合NLP识别变种敏感词
  4. 分级过滤:设置不同敏感级别阈值

结语

本文实现的AC自动机方案,在Flutter应用中达到了平均3ms/千字符的处理速度。相较于传统方案,在保证精度的同时实现了性能的飞跃。建议将敏感词库维护作为长期工作,结合业务场景持续优化,构建全方位的内容安全体系。

完整代码示例如下

import 'dart:convert';

import "package:flutter/services.dart";

// 敏感词过滤器(基于 AC 自动机实现)
class SensitiveWordsFilter {
  // Trie 树根节点
  static final Map<String, dynamic> _root = {};
  static bool _isBuilt = false;

  // 可扩展的干扰字符
  static final Set<String> _ignoreChars = {'-', '_', '*', '#', ' '};

  // 加载敏感词列表并构建 Trie 树
  static Future<void> loadSensitiveWords() async {
    try {
      final jsonString =
          await rootBundle.loadString('assets/words/sensitive_words.json');
      final sensitiveWordsData = jsonDecode(jsonString);

      var listData = sensitiveWordsData['words']['list'];
      if (listData is List) {
        _buildTrie(List<String>.from(listData));
        print("Sensitive words loaded successfully.");
      } else {
        print("Error: 'list' field is not a valid List.");
      }
    } catch (e) {
      print("Load error: $e");
    }
  }

  // 构建 Trie 树
  static void _buildTrie(List<String> words) {
    _root.clear();

    for (var word in words) {
      var node = _root;
      for (var char in word.toLowerCase().split('')) {
        node = node.putIfAbsent(char, () => <String, dynamic>{})
            as Map<String, dynamic>;
      }
      node['isEnd'] = true; // 标记敏感词结束
    }

    // 构建 fail 指针
    final queue = <Map<String, dynamic>>[];
    for (var entry in _root.entries) {
      if (entry.value is Map<String, dynamic>) {
        var child = entry.value as Map<String, dynamic>;
        child['fail'] = _root;
        queue.add(child);
      }
    }

    while (queue.isNotEmpty) {
      var parentNode = queue.removeAt(0);
      for (var entry in parentNode.entries) {
        if (entry.key == 'fail' || entry.key == 'isEnd') continue;

        var char = entry.key;
        var childNode = entry.value as Map<String, dynamic>;

        // 回溯 fail 指针
        var failNode = parentNode['fail'] as Map<String, dynamic>? ?? _root;
        while (failNode != _root && !failNode.containsKey(char)) {
          failNode = failNode['fail'] as Map<String, dynamic>? ?? _root;
        }

        childNode['fail'] = failNode[char] ?? _root;

        if ((failNode[char] as Map<String, dynamic>?)?.containsKey('isEnd') ??
            false) {
          childNode['isEnd'] = true;
        }

        queue.add(childNode);
      }
    }

    _isBuilt = true;
  }

  // 检查消息是否包含敏感词
  static bool containsSensitiveWords(String message) {
    if (!_isBuilt) {
      throw Exception('敏感词列表未初始化');
    }

    int index = 0;
    final lowerMessage = message.toLowerCase();

    while (index < lowerMessage.length) {
      var node = _root;
      int tempIndex = index;

      while (tempIndex < lowerMessage.length) {
        var char = lowerMessage[tempIndex];

        // 如果是干扰字符,跳过但不更新节点
        if (_ignoreChars.contains(char)) {
          tempIndex++;
          continue;
        }

        // 失配时,沿着 fail 指针回退
        while (node != _root && !node.containsKey(char)) {
          node = node['fail'] as Map<String, dynamic>? ?? _root;
        }

        node = node[char] as Map<String, dynamic>? ?? _root;

        // 如果当前节点是敏感词结尾,返回 true
        if (node.containsKey('isEnd')) return true;

        tempIndex++;
      }

      index++;
    }

    return false;
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2326300.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Odoo/OpenERP 和 psql 命令行的快速参考总结

Odoo/OpenERP 和 psql 命令行的快速参考总结 psql 命令行选项 选项意义-a从脚本中响应所有输入-A取消表数据输出的对齐模式-c <查询>仅运行一个简单的查询&#xff0c;然后退出-d <数据库名>指定连接的数据库名&#xff08;默认为当前登录用户名&#xff09;-e回显…

Vue中使用antd-table组件时,树形表格展开配置不生效-defaultExpandedRowKeys-默认展开配置不生效

defaultExpandedRowKeys属性 defaultExpandAllRows这个属性仅仅是用来设置默认值的,只在第一次渲染的时候起作用,后续再去改变,无法实现响应式 解决方案一 a-table表格添加key属性,当每次获取值时,动态改变key,以达到重新渲染的效果 <a-table:key="tableKey"…

VRRP交换机三层架构综合实验

题目要求&#xff1a; 1&#xff0c;内网Ip地址使用172.16.0.0/16分配 说明可以划分多个子网&#xff0c;图中有2个VLAN&#xff0c;可以根据VLAN划分 2&#xff0c;sw1和SW2之间互为备份 互为备份通常通过VRRP&#xff08;虚拟路由冗余协议&#xff09;来实现。VRRP会在两个…

基于卷积神经网络的眼疾识别系统,resnet50,efficentnet(pytorch框架,python代码)

更多图像分类、图像识别、目标检测、图像分割等项目可从主页查看 功能演示&#xff1a; 眼疾识别系统resnet50&#xff0c;efficentnet&#xff0c;卷积神经网络&#xff08;pytorch框架&#xff0c;python代码&#xff09;_哔哩哔哩_bilibili &#xff08;一&#xff09;简介…

基于srpingboot智慧校园管理服务平台的设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…

【力扣hot100题】(026)合并两个有序链表

可以创建一个新链表记录答案&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *…

TCP网络编程与多进程并发实践

一、引言 在网络编程中&#xff0c;TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议。而多进程并发则是一种提高服务器处理能力的有效手段&#xff0c;允许服务器同时处理多个客户端的请求。本文将详细介绍如何使用 TCP 协议进…

visio导出pdf公式变形

情况描述导出为pdf后&#xff0c;mathtype写的公式就变形了 但是导出为png和jpg就是正常 解决方法就是 需要下载一个Adobe Acrobat

【学习笔记】计算机网络(六)

第6章应用层 文章目录 第6章应用层6.1 域名系统DNS6.1.1 域名系统概述6.1.2 互联网的域名结构6.1.3 域名服务器域名服务器的分区管理DNS 域名服务器的层次结构域名服务器的可靠性域名解析过程-两种查询方式DNS 高速缓存机制 6.2 文件传送协议6.2.1 FTP 概述6.2.2 FTP 的基本工作…

量子退火与机器学习(2):少量实验即可找到新材料,黑盒优化➕量子退火

使用量子退火和因子分解机设计新材料 这篇文章是东京大学的一位博士生的毕业论文中的主要贡献。 结合了黑盒优化和量子退火&#xff0c;是融合的非常好的一篇文章&#xff0c;在此分享给大家。 https://journals.aps.org/prresearch/abstract/10.1103/PhysRevResearch.2.0133…

【React】基于 React+Tailwind 的 EmojiPicker 选择器组件

1.背景 React 写一个 EmojiPicker 组件&#xff0c;基于 emoji-mart 组件二次封装。支持添加自定义背景 、Emoji 图标选择&#xff01;并在页面上展示&#xff01; 2.技术栈 emoji-mart/data 、emoji-mart : emoji 图标库、元数据 tailwindcss: 原子化 CSS 样式库 antd : 组…

02-Docker 使用

docker:快速构建、运行、管理应用的工具,可以帮助我们下载应用镜像,创建并运行镜像的容器,从而快速部署应用 1、部署mysql 先停掉虚拟机中的MySQL,确保你的虚拟机已经安装Docker,且网络开通的情况下,执行下面命令即可安装MySQL(注意:若服务器上已经有mysql 占用了330…

html5时钟升级!支持切换深浅模式 Canvas实现现代化动态时钟

HTML5 Canvas实现现代化动态时钟 这里写目录标题 HTML5 Canvas实现现代化动态时钟项目介绍技术实现1. 项目架构2. Canvas绘图实现2.1 表盘绘制2.2 刻度绘制2.3 指针绘制 3. 动画效果4. 主题切换 项目亮点技术要点总结项目收获改进方向结语 项目介绍 本项目使用HTML5 Canvas技术…

MOE-1 基本认识

解读一下MOE架构&#xff0c;部分内容图片参考自油管。 首先来简单了解一下什么是MoE&#xff08;Mixture of Experts&#xff0c;专家混合&#xff09; MoE&#xff08;Mixture of Experts&#xff09;是一种深度学习架构&#xff0c;其核心思想是通过**多个专家网络&#xf…

【C++接入大模型】WinHTTP类封装:实现对话式大模型接口访问

一、类设计概述 近期准备用C做一些大预言模型方面的开发&#xff0c;先期计划实现C调用公共的大模型Web接口&#xff0c;因为之前没做过C的Web开发&#xff0c;经验少&#xff0c;所以对比了一些主流的框架&#xff0c;包括实际测试验证。以下是Windows平台下主流C HTTP库的对…

【银河麒麟高级服务器操作系统 】虚拟机运行数据库存储异常现象分析及处理全流程

更多银河麒麟操作系统产品及技术讨论&#xff0c;欢迎加入银河麒麟操作系统官方论坛 https://forum.kylinos.cn 了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer…

文件分享系统--开源的可视化文件共享管理工具

家里有公网&#xff0c;经常要发文件给别人&#xff0c;文件几个G发送还要云盘或者倒手一次才行&#xff0c;所以弄了个文件分享系统&#xff0c;这个是用字节的 AI Trae 写的&#xff0c;反正反复折腾还是弄出来了。东西挺好用&#xff0c;可以拖拽多个文件上传也可以手动添加…

【力扣刷题实战】寻找数组的中心下标

大家好&#xff0c;我是小卡皮巴拉 文章目录 目录 力扣题目&#xff1a;寻找数组的中心下标 题目描述 解题思路 问题理解 算法选择 具体思路 解题要点 完整代码&#xff08;C&#xff09; 兄弟们共勉 &#xff01;&#xff01;&#xff01; 每篇前言 博客主页&#…

LearnOpenGL小练习(QOpenGLWidget版本)

你好&#xff0c;三角形 1.绘制两个彼此相连的三角形 画两个独立的三角形&#xff0c;给出两个三角形顶点&#xff0c;使用GL_TRIANGLES绘图即可。 关键代码 void MyOpenglWgt::initializeGL() {initializeOpenGLFunctions(); // 1. 创建ShaderProgram着色器&#xff1a;加…

基于OpenCV+MediaPipe手部追踪

一、技术栈 1. OpenCV&#xff08;Open Source Computer Vision Library&#xff09; 性质&#xff1a;开源计算机视觉库&#xff08;Library&#xff09; 主要功能&#xff1a; 图像/视频的基础处理&#xff08;读取、裁剪、滤波、色彩转换等&#xff09; 特征检测&#xf…