DFA 算法

为什么要学习这个算法

  前一段时间遇到了瓶颈,因为词库太多了导致会有一些速度过慢,而且一个正则表达式已经放不下了,需要进行拆分正则才可以。

正好我以前看过有关 dfa 的介绍,但是并没有深入的进行研究,所以就趁着周末好好的了解一下这个东西。跟 php 的正则进行一下对比,看看速度如何,如果表现较好,说不定还能用得上。

什么是 dfa

通过百度可以知道 dfa 是 确定有穷自动机 的缩写。 应该还会见到类似下面图的说明

原谅我实在一些,我这人数学不好不说,貌似看图能力也不行,这个图恕我直言我没看懂。所以关于精准的解释,请大家去百度或者 google 自行查阅了。

我的理解

说明之前,我们先看看做检测需要准备的东西

  • 一个组织好的关键词树
  • 待检测的字符串

什么是组织好的关键词树

我们一批需要检测词库,比如下面这些

日本人,日本鬼子,日本人傻,破解*版

先做个解释,前三个大家都能看懂,那么 * 是什么,这个是我定义的通配符,代表着 * 可以是 0 - n 个占位符用来替代在关键词中间插入混淆字符。至于可以替换几个我们可以在代码中进行定义,需要注意 n 越大,速度就会越慢。

说明完了,来看看构造好的树是什么一样的,应该是跟下图差不多的。

为什么要手动画一个,因为需要对比,我的理解跟程序是否一致,如果不一致,就要找出程序是不是写的不对了。那么我们来看看程序生成的是啥样的。

程序生成的跟图片一致,到这里还都是正确的。

待检测的字符串

这个就很容易理解了,就是我们需要检测的字符串。

为什么要组织好那样的一棵树(算法思路)

这块需要先说一个概念

它是是通过event和当前的state得到下一个state,即event+state=nextstate

这句话,或者类似的话你会在绝大多数的解释文章里面看到。而我的理解就是,一个字符一个字符的检测,如果检测的字符在我们的树种,就进入命中的树,看下一个字在不在树里面,如果持续的命中就持续进入,最后完全命中了,也就是那个字的子树只有一个元素,并且元素的键是 end (这里是在我们的这个例子中,看图就明白了)。就是完全命中了关键词,就可以记录命中,或者准备替换了。

这里说一个可以优化的点,看我们的例子有两个词 日本人,日本鬼子 这两个,如果为了快,完全可以去掉第二个词,质保流一个就行了,这样当检测到 end 就可以直接屏蔽或者记录了,而在我们的例子中,还需要判断元素数量,不是 1 的情况下还得继续深入,看看是不是命中了长尾。

这样的长尾检测会引发一个问题,那就是 回滚,当我们命中了前置的词,后续的没有命中的时候就得记录并且回滚,这个回滚的长度是是多少呢?其实不仅仅是没有命中长尾的回滚,还有一个 回滚 操作,就是检测率几个字之后就没命中率额,就得回顾,这个回滚的长度是,已检测字符长度 - 1 的长度 。那么没有命中长尾的长度我们就知道了,已检测字符长度 - 上次命中的长度 就可以了。

下面我们来看看代码实现。

// 通配符的数量
$maskMin = 0;
$maskMax = 3;
// 关键词词典字符串,这个部分的处理自己可以替换
$dict = "傻瓜";
$checkDfaTree = [];
$dictArr = explode(',', $dict);
// 重组一下带有 * 通配符的数组
$fullDictArr = [];
foreach ($dictArr as $word) {if (mb_strpos($word, '*') !== false) {// 带有通配符就把通配符去掉for ($maskIndex = $maskMin; $maskIndex <= $maskMax; $maskIndex++) {$maskString = str_pad('', $maskIndex, '*');$inputWord = str_replace('*', $maskString, $word);$fullDictArr[] = $inputWord;}} else {$fullDictArr[] = $word;}
}foreach ($fullDictArr as $word) {// 每次开始新词都要回到树的根部$treeStart = &$checkDfaTree;$wordLen = mb_strlen($word);for ($i = 0; $i < $wordLen; $i++) {$char = mb_substr($word, $i, 1);$treeStart[$char] = isset($treeStart[$char]) ? $treeStart[$char] : [];if ($i + 1 == $wordLen) {// 如果已经是次的结尾了就设置null$treeStart[$char]['end'] = true;}// 移动指针到下一个$treeStart = &$treeStart[$char];}
}
// 遍历str
$start = microtime(true);
$checkMessageLen = mb_strlen($checkMessage);
$wordArr = [];
$checkTreeStart = &$checkDfaTree;
$hasPrefixLength = 0;
$targetWord = '';for ($i = 0; $i < $checkMessageLen; $i++) {// 获取一个字符$char = mb_substr($checkMessage, $i, 1);if (isset($checkTreeStart[$char])) {// 如果有这个字就进入子树里面if (isset($checkTreeStart[$char]['end']) && $checkTreeStart[$char]['end'] === true) {// 如果包含这个标识,就记录标识$hasPrefixLength = mb_strlen($targetWord);}$checkTreeStart = &$checkTreeStart[$char];$targetWord .= $char;} else if (isset($checkTreeStart['*'])) {// 如果有通配符就进入子树$checkTreeStart = &$checkTreeStart['*'];$targetWord .= $char;} else {if ($hasPrefixLength) {$wordArr[] = mb_substr($targetWord, 0, $hasPrefixLength + 1);// 回滚$i -= mb_strlen($targetWord) - $hasPrefixLength;} else {// 回滚$i -= mb_strlen($targetWord);}// 回到头部$checkTreeStart = &$checkDfaTree;$targetWord = '';$hasPrefixLength = 0;}if (count($checkTreeStart) == 1 && isset($checkTreeStart['end']) && $checkTreeStart['end'] === true) {// 子树只有一个并且是end 就说明是命中了// 赋值$wordArr[] = $targetWord;// 清空$targetWord = '';// 回到头部$checkTreeStart = &$checkDfaTree;$hasPrefixLength = 0;}
}
var_dump($wordArr);
echo "<br /> useTime:" . (microtime(true) - $start) * 1000;

下面这个就是匹配加测试了,目前我能想到的都测试通过了,如果有问题,可以回复我。

结论

目前来看,效率是比正则要好一些,命中的情况下速度差不多,没命中的情况下表现要优于正则。

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

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

相关文章

词条唤夜兽唤夜兽的养殖与护理 幻兽帕鲁 唤夜兽怎么获取 唤夜兽去哪里抓 crossover玩Steam游戏

唤夜兽在地图上没有出现&#xff0c;是唤冬兽和雷冥鸟共同培育出来的帕鲁。 ------------------------- 介绍&#xff1a; 帕洛斯群岛之守护神&#xff0c;拥呼唤黑夜之力。 其会于灾厄席捲大地之际腾空而起&#xff0c;唤来无尽暗夜&#xff0c;试图封印灾厄。 ---------…

mac操作系统下,docker登录nexus私库,提示不支持https协议的错误

一、背景 我们使用nexus搭建了一个Docker Registry私有仓库&#xff0c;在Mac操作系统&#xff0c;在推送本地镜像到私库前&#xff0c;要求我们登录私库&#xff0c;报错如下&#xff1a; docker login 192.168.5.6:8086 -u username -p passwordWARNING! Using --password …

设计模式10——装饰模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用&#xff0c;主要是下面的UML图可以起到大作用&#xff0c;在你学习过一遍以后可能会遗忘&#xff0c;忘记了不要紧&#xff0c;只要看一眼UML图就能想起来了。同时也请大家多多指教。 装饰模式 是一种行为型模式。…

推荐丨快速申请免费域名证书

背景&#xff1a; 域名是一个IP地址上的“面具” 。一个域名的目的是便于记忆和沟通的一组服务器的地址(网站&#xff0c;电子邮件&#xff0c;FTP等)。 通俗的说&#xff0c;域名就相当于一个家庭的门牌号码&#xff0c;别人通过这个号码可以很容易的找到你。 域名不仅便于记…

Facebook广告如何开户以及投放费用?

Facebook作为全球最大的社交媒体平台之一&#xff0c;成为了企业与个人推广品牌、产品或服务的重要渠道。其精准的广告定向功能和庞大的用户基数&#xff0c;为广告主提供了无限的商机。云衔科技为企业提供专业的Facebook上开户和运营服务&#xff0c;助力您高效获客。 一、Fa…

Go 1.23 Release Notes编写方式改进!

2024.5.22日&#xff0c;Go 1.23 feature冻结&#xff01;Go团队开始Go 1.23rc1的冲刺&#xff0c;截至发文时&#xff0c;Go 1.23 milestone已经完成59%(https://github.com/golang/go/milestone/212)&#xff0c;还有188个open的issue待解决。 Go 1.23有哪些新feature&#x…

YAML详情

一、kubernetes支持对象 Kubernetes支持YAML和JSON格式管理资源对象 JSON格式&#xff1a;主要用于api接口之间消息的传递YAML格式&#xff1a;用于配置和管理&#xff0c;YAML是一种简洁的非标记性语言&#xff0c;内容格式人性化&#xff0c;较易读 二、YAML语法格式注意点 …

Octo 精武门? :开源的通用机器人模型

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调重新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;则提供了大模型领域最新技…

【C++ —— 哈希】学习笔记 | 模拟实现封装unordered_map和unordered_set

文章目录 前言一、unordered系列关联式容器1.1 unordered_map1.2 unordered_set 二、底层结构2.1哈希概念&#xff08;哈希是一种算法思想&#xff09;2.2哈希冲突2.3 解决哈希冲突方法&#xff1a;1.直接定址法&#xff08;值和位置关系是唯一关系&#xff0c;每个人都有唯一位…

NextJs 初级篇 - 安装 | 路由 | 中间件

NextJs 初级篇 - 安装 | 路由 | 中间件 一. NextJs 的安装二. 路由2.1 路由和页面的定义2.2 布局的定义和使用2.3 模板的定义和使用① 模板 VS 布局② 什么是 use client 2.4 路由跳转的方式2.5 动态路由2.6 路由处理程序① GET 请求的默认缓存机制② 控制缓存或者退出缓存的手…

大模型效能工具之智能CommitMessage

01 背景 随着大型语言模型的迅猛增长&#xff0c;各种模型在各个领域的应用如雨后春笋般迅速涌现。在研发全流程的效能方面&#xff0c;也出现了一系列贯穿全流程的提效和质量工具&#xff0c;比如针对成本较高的Oncall&#xff0c;首先出现了高质量的RAG助手&#xff1b;在开…

山东大学软件学院数据库实验1-9(全部)

目录 前言 实验代码 实验一 1-1 1-2 1-3 1-4 1-5 1-6 实验二 2-1 2-2 2-3 2-4 2-5 2-6 2-7 2-8 2-9 2-10 实验三 3-1 3-2 3-3 3-4 3-5 3-6 3-7 3-8 3-9 3-10 实验四 4-1 4-2 4-3 4-4 4-5 4-6 4-7 4-8 4-9 4-10 实验五 5-1…

鹏特资本进入中国市场具有以下一些优势

1. 带来资金&#xff1a;补充国内资金缺口&#xff0c;为企业发展和项目建设提供重要的资金支持。 2. 先进技术和管理经验&#xff1a;有助于推动技术创新和管理水平提升&#xff0c;促进产业升级和优化。 3. 促进竞争&#xff1a;激发国内市场活力&#xff0c;促使本土企业不…

解决 Failed to parse remote port from server output【Remote-SSH】【VSCode】

描述 一早起来&#xff0c;发现remote-ssh无法进入服务器容器&#xff0c;本地使用git bash进行ssh可正常连接服务器&#xff0c;基本确定是vscode工具本身的问题。重装本地用户的.vscode相关目录清空&#xff0c;vscode重装均无果&#xff0c;不建议尝试。弹窗信息为Could no…

【课程作业】嵌入式系统与设计上机作业(作业三)

个人名片&#xff1a; &#x1f393;作者简介&#xff1a;嵌入式领域优质创作者&#x1f310;个人主页&#xff1a;妄北y &#x1f4de;个人QQ&#xff1a;2061314755 &#x1f48c;个人邮箱&#xff1a;[mailto:2061314755qq.com] &#x1f4f1;个人微信&#xff1a;Vir2025WB…

Ant Design pro 6.0.0 搭建使用以及相关配置

一、背景 在选择一款比较合适的中台的情况下&#xff0c;挑选了有arco design、ant design pro、soybean、vue-pure-admin等中台系统&#xff0c;经过筛选就选择了ant design pro。之前使用过arco design 搭建通过组件库拼装过后台管理界面&#xff0c;官方文档也比较全&#…

2024GDCPC广东省赛记录

比赛流程体验&#xff0c;依托&#xff0c;开赛几分钟了&#xff0c;选手还卡在门外无法入场&#xff0c;也没给延时&#xff0c;说好的桌上会发三支笔&#xff0c;于是我们就没准备&#xff0c;要了三次笔&#xff0c;终于在一小时后拿到了&#x1f605; 比赛题目体验&#xf…

Java基础22(JSON解析 注解)

目录 一、JSON解析 1. JSON语法 2. JSON的用途 3. Java解析JSON 4. 使用Fastjson 4.1 Fastjson 的优点 4.2 Fastjson 导包 4.3 Fastjson的主要对象 4.4 常用方法 将Java对象 "序列化"&#xff08;转换&#xff09; 为JSON字符串&#xff1a; 将JSON字符串…

YOLOv5改进策略:Focaler-IoU损失函数改进

文章目录 1、前言2、摘要3、Focaler-IoU&#xff1a;4、代码实现5、目标检测系列文章 1、前言 ​ 目标检测是计算机视觉的基本任务之一&#xff0c;旨在识别图像中的目标并定位其位置。目标检测算法可分为基于锚点和无锚点的方法。基于锚点的方法包括Faster R-CNN、YOLO系列、…

详细分析Element Plus中的ElMessageBox弹窗用法(附Demo及模版)

目录 前言1. 基本知识2. Demo3. 实战4. 模版 前言 由于需要在登录时&#xff0c;附上一些用户说明书的弹窗 对于ElMessageBox的基本知识详细了解 可通过官网了解基本的语法知识ElMessageBox官网基本知识 1. 基本知识 Element Plus 是一个基于 Vue 3 的组件库&#xff0c;其中…