(正则引擎已完成,Github)

最小化 DFA 是引擎中另外一个略繁琐的点(第一个是构建语法树)。

基本思路是,先对 DFA 进行重命名,然后引入一个拒绝态 0,定义所有状态经过非接受字符转到状态 0,0 接受所有字符转换为自身。也就是说我们先建立一个转换表,然后把第一行填写为:

state a b c d e f g h ...
0 0 0 0 0 0 0 0 0 0

再之后,我们讲 DFA 的其余状态从 1 开始重命名,填入状态表。代码实现如下:

        // rename all statesfor (Set<NFAState> nfaState : oriDFATransitionMap.keySet()) {if (initStateAfterRenaming == -1 && nfaState.equals(initClosure)) {initStateAfterRenaming = renamingStateID; // record init state id}stateRenamingMap.put(nfaState, renamingStateID++);}renamedDFATransitionTable.put(0, newRejectState()); // the reject state 0finalFlags.put(0, false);// construct renamed dfa transition tablefor (Map.Entry<Set<NFAState>, Map<Character, Set<NFAState>>> entry : oriDFATransitionMap.entrySet()) {renamingStateID = stateRenamingMap.get(entry.getKey());int[] state = newRejectState();for (Map.Entry<Character, Set<NFAState>> row : entry.getValue().entrySet()) {state[row.getKey()] = stateRenamingMap.get(row.getValue());}renamedDFATransitionTable.put(renamingStateID, state);if (entry.getKey().contains(finalNFAState)) {finalFlags.put(renamingStateID, true);} else finalFlags.put(renamingStateID, false);}

这里有一个 finalFlags 用来记录哪些 DFA 的终态包含了 NFA 的终态 1。(这些状态都作为 DFA 的终态)

接下来,把所有状态分为终态作为一个 group,非终态作为另一个 group:

        // split states to final states and non-final statesMap<Integer, Integer> groupFlags = new HashMap<>();for (int i = 0; i < finalFlags.size(); i++) {boolean b = finalFlags.get(i);if (b) groupFlags.put(i, 0);else groupFlags.put(i, 1);}

我们定义任意 group 中的任意状态的转换规则为:接受某个字符转移到某个 group(区别于转换到某个状态)。

不停地遍历所有的 group,把同一个 group 中具有不同转换规则的状态分隔为不同的 group。

        do { // splitting, group id is the final state idpreGroupTotal = groupTotal;for (int sensitiveGroup = 0; sensitiveGroup < preGroupTotal; sensitiveGroup++) {//  <target group table, state id set>Map<Map<Integer, Integer>, Set<Integer>> invertMap = new HashMap<>();for (int sid = 0; sid < groupFlags.size(); sid++) { //use state id to iterateint group = groupFlags.get(sid);if (sensitiveGroup == group) {Map<Integer, Integer> targetGroupTable = new HashMap<>(CommonSets.ENCODING_LENGTH);for (char ch = 0; ch < CommonSets.ENCODING_LENGTH; ch++) {int targetState = renamedDFATransitionTable.get(sid)[ch];int targetGroup = groupFlags.get(targetState);targetGroupTable.put((int) ch, targetGroup);}Set<Integer> stateIDSet = invertMap.get(targetGroupTable);if (stateIDSet == null) {stateIDSet = new HashSet<>();invertMap.put(targetGroupTable, stateIDSet);}stateIDSet.add(sid); // gather all sids having the same target group table into this set}}boolean first = true;for (Set<Integer> stateIDSet : invertMap.values()) {if (first) {first = false;} else {for (int sid : stateIDSet) {groupFlags.put(sid, groupTotal);}groupTotal++;}}}} while (preGroupTotal != groupTotal);

如此分到不可再分,再把每一个 group 中的所有状态合并为同一个状态,这样我们就得到了 group 个状态,就完成了 DFA 的最小化。

接着是再次确定整个 DFA 的初态、终态和拒绝态。我们只要把包含这些状态的 group 作为最小化之后的相应状态就可以了。

        // determine initial group stateis = groupFlags.get(initStateAfterRenaming);// determine reject group staters = groupFlags.get(0);// determine final group statesSet<Integer> finalGroupFlags = new HashSet<>();for (int i = 0, groupFlagsSize = groupFlags.size(); i < groupFlagsSize; i++) {Integer groupFlag = groupFlags.get(i);if (finalFlags.get(i)) {finalGroupFlags.add(groupFlag);}}fs = new boolean[groupTotal];for (int i = 0; i < groupTotal; i++) {fs[i] = finalGroupFlags.contains(i);}

最后一步是把 DFA 转换为一个以数组形式存放的状态表,就可以用来进行快速而准确的正则匹配了。

        // construct the final transition tabletransitionTable = new int[groupTotal][];for (int groupID = 0; groupID < groupTotal; groupID++) {for (int sid = 0; sid < groupFlags.size(); sid++) {if (groupID == groupFlags.get(sid)) {int[] oriState = renamedDFATransitionTable.get(sid);int[] state = new int[CommonSets.ENCODING_LENGTH];for (char ch = 0; ch < CommonSets.ENCODING_LENGTH; ch++) {int next = oriState[ch];state[ch] = groupFlags.get(next);}transitionTable[groupID] = state;break;}}}

至此,我们的整个 DFA 正则表达式引擎就构建完成了。

之后我用一个 apache log 的正则做了一下性能测试,这个引擎的匹配速度比 JDK 自带的正则要快至少一倍,还是有一定的实用性的,所以我把它放到了 Github 上,欢迎下载源码。

个人水平有限,代码中一定有不少尚待优化的地方,如有建议请不吝赐教。

转载于:https://www.cnblogs.com/zbdzzg/p/4509326.html

实现一个 DFA 正则表达式引擎 - 4. DFA 的最小化相关推荐

  1. dfa算法 java_DFA算法的实现与最小化

    有限自动机分为确定有限自动机(DFA)和不确定有限自动机(NFA),这里介绍DFA,即确定有限自动机. 1. DFA的形式定义 从形式上说,一个有限状态自动机可以用下面的5个参数来定义: Q: 状态q ...

  2. 实现一个正则表达式引擎in Python(一)

    前言 项目地址:Regex in Python 开学摸鱼了几个礼拜,最近几天用Python造了一个正则表达式引擎的轮子,在这里记录分享一下. 实现目标 实现了所有基本语法 st = 'AS342abc ...

  3. 编译原理: 最小化 DFA(划分) 验证 DFA(Kleene 闭包)

    编译原理: 最小化 DFA(划分) & 验证 DFA(Kleene 闭包) 文章目录 编译原理: 最小化 DFA(划分) & 验证 DFA(Kleene 闭包) 简介 参考 正文 示例 ...

  4. 编译原理学习笔记(十五)~最小化DFA

    概念 最小化:优化DFA,使其状态数最少. 那么什么时候状态数是最少的呢?这里我们需要介绍两个新的名词:可区分和不可区分. 官方定义:         可区分:对于任何两个状态t和s,若从一状态出发接 ...

  5. 正则表达式引擎的构建——基于编译原理DFA(龙书第三章)——1 概述

    说明:本系列文章介绍的算法均来自编译原理(龙书)一书,如果读者对代码没有兴趣,只想了解算法思路,完全可以阅读龙书相关章节内容,比我讲得清晰透彻. 序: 啃编译原理半年以来,任然徘徊在前4章,其间反反复 ...

  6. 正则表达式引擎的构建——基于编译原理DFA(龙书第三章)——5 DFA最小化

    完整引擎代码在github上,地址为:https://github.com/sun2043430/RegularExpression_Engine.git DFA最小化的算法原理 "DFA状 ...

  7. 实现一个正则表达式引擎in Python(三)

    项目地址:Regex in Python 前两篇已经完成的写了一个基于NFA的正则表达式引擎了,下面要做的就是更近一步,把NFA转换为DFA,并对DFA最小化 DFA的定义 对于NFA转换为DFA的算 ...

  8. 实现一个正则表达式引擎in Python(二)

    项目地址:Regex in Python 在看一下之前正则的语法的 BNF 范式 group ::= ("(" expr ")")* expr ::= fact ...

  9. 正则表达式转NFA,DFA,最小化DFA

    Exp 2:正则表达式转NFA,DFA,最小化DFA (1)正则表达式应该支持单个字符,运算符号有: 连接 选择(|) 闭包(*) 正闭包(+) 可选(?) 括号 (2)要提供一个源程序编辑界面,让用 ...

最新文章

  1. Neuron最新研究:神经科学家测量球迷大脑对比赛的反应,试图挖掘人类的深层天性...
  2. Swift3.0温习之基础篇
  3. 查看线程CPU利用率
  4. ap.net core 教程(三)
  5. tp5 自定义配置文件
  6. BrainOS —最像大脑的AI
  7. tomcat按日期分割日志(官网文档推荐实现)
  8. 软件项目总结报告范文
  9. IOUtils常用方法的使用
  10. RIDE加载Selenium2Library总是显示红色的解决办法
  11. advanced部署vsto到wps-兼容office和wps
  12. linux内核的裁剪与移植
  13. 弹性地基梁板的计算理论_第八章 弹性地基梁的计算理论
  14. logisitic 回归 +极大似然法 + 梯度下降法 (迭代优化)
  15. JavaScript-WebAPIs学习记录
  16. 新物联网!新电商平台!
  17. Tanya出了新碟,这让我想起来了高中时听她的记念
  18. 本体李俊|区块链的实际业务场景需要哪些技术模块?
  19. 【ceph】什么是Ceph?------(MinIO和ceph的区别|GFS(GlusterFS)、MFS、Ceph、Lustre|文档)...
  20. c51语言case是什么意思,单片机入门-C51语言switch-case语句电路应用实例

热门文章

  1. 哪个网站是计算机知识的,电脑知识网站
  2. [linux]ps结果计算行数
  3. mfc存储颜色到mysql_mfc存储二进制文件
  4. 徐州事业单位计算机软件类,徐州计算机办公应用软件
  5. smartqq java撤回_基于nodejs的http模块通过smartqq实现自动收发qq消息的程序
  6. 并联串联混合的电压和电流_电流互感器一次绕组串联、并联,二次绕组串联、并联的相关问题...
  7. python升级pip怎么出错了_Python,开启吐槽模式,新手必看!
  8. ppp chap 加密摘要_“网络工程师培训”基础教程:一文读懂PPP协议
  9. 科技复原,让 3000 多前年的木乃伊「发声」
  10. 二叉树的层次遍历_【腾讯面试热身题】二叉树层次遍历(动画展示)