一个只能匹配非常简单的(字母 . + *)共 4 种状态的正则表达式语法的自动机(注意,仅限 DFA,没考虑 NFA):

  好久之前写的了,记得有个 bug 一直没解决...

  1. #include <iostream>
  2. //#include <fstream>
  3. #include <vector>
  4. #include <string>
  5.  
  6. class DFA
  7. {
  8. void construction(std::string regex)
  9. {
  10. std::vector<AM*> worker;
  11. Match = std::make_unique<AM>();
  12. h = std::make_unique<AM>(toRange('H'), nullptr);
  13. AM* h_ptr = h.get();
  14. for (auto iter = regex.begin(); iter != regex.end(); ++iter)
  15. {
  16. AM * temp = new AM(toRange(*iter), h_ptr);
  17. switch (*iter)
  18. {
  19. case '.':
  20. {
  21. h_ptr->next[temp->ch] = temp;
  22. h_ptr = temp;
  23. if (iter + 1 != regex.end() && *(iter + 1) != '*')
  24. {
  25. while (!worker.empty())
  26. {
  27. AM*c_ptr = worker.front();
  28. worker.erase(worker.begin());
  29. c_ptr->next[h_ptr->ch] = h_ptr;
  30. }
  31. }
  32. }
  33. break;
  34. case '*':
  35. {
  36. h_ptr->next[h_ptr->ch] = h_ptr;
  37. for (std::vector<AM*>::iterator i = worker.begin(); i != worker.end(); i++)
  38. (*i)->next[h_ptr->ch] = h_ptr;
  39. if (h_ptr->prev != nullptr)
  40. worker.push_back(h_ptr->prev);
  41. worker.push_back(h_ptr);
  42. delete temp;
  43. temp = nullptr;
  44. }
  45. break;
  46. case '+':
  47. {
  48. h_ptr->next[h_ptr->ch] = h_ptr;
  49. while (!worker.empty())
  50. {
  51. AM*c_ptr = worker.front();
  52. worker.erase(worker.begin());
  53. c_ptr->next[h_ptr->ch] = h_ptr;
  54. }
  55. delete temp;
  56. temp = nullptr;
  57. }
  58. break;
  59. default:
  60. {
  61. h_ptr->next[temp->ch] = temp;
  62. h_ptr = temp;
  63. if (iter + 1 != regex.end() && *(iter + 1) != '*')
  64. {
  65. while (!worker.empty())
  66. {
  67. AM*c_ptr = worker.front();
  68. worker.erase(worker.begin());
  69. c_ptr->next[h_ptr->ch] = h_ptr;
  70. }
  71. }
  72. }
  73. break;
  74. }
  75. }
  76. while (!worker.empty())
  77. {
  78. AM*c_ptr = worker.front();
  79. worker.erase(worker.begin());
  80. if (h_ptr->next[h_ptr->ch] == h_ptr)
  81. c_ptr->next[0] = Match.get();
  82. else
  83. c_ptr->next[h_ptr->ch] = h_ptr;
  84. }
  85. h_ptr->next[0] = Match.get();
  86. }
  87.  
  88. char toRange(char c) const
  89. {
  90. if (c == '.')
  91. return 27;
  92. return c - 'a' + 1;
  93. }
  94.  
  95. public:
  96. bool isMatch(std::string s, std::string regex)
  97. {
  98. construction(regex);
  99. AM * am = h.release();
  100. for (auto i:s)
  101. {
  102. char c = toRange(i);
  103. if (am == nullptr)
  104. return false;
  105. if (am->next[c] != nullptr)
  106. am = am->next[c];
  107. else if (am->next[27] != nullptr)
  108. am = am->next[27];
  109. else
  110. am = am->next[c];
  111. }
  112. return am != nullptr && am->next[0] == Match.get();
  113. }
  114.  
  115. private:
  116. struct AM {
  117. char ch;
  118. AM *prev, *next[28];
  119. AM() : ch(), prev(), next() {}
  120. AM(char v, AM * prev) : ch(v), prev(prev), next() {}
  121. };
  122.  
  123. std::unique_ptr<AM> Match, h;
  124. };
  125.  
  126. int main(int argc, char const *argv[])
  127. {
  128. DFA s;
  129.  
  130. std::cout << (s.isMatch("abc", "aa*b*c+p*") ? "true":"false");
  131.  
  132. return 0;
  133. }

  示例1:a*b*c+d*

  该正则表达式的DFA如下图

  示例2:(a|b)*a

  这是一个NFA,我的代码并没有实现NFA转DFA,因而会导致匹配失败。(2020-04-05 21:00:39 补充:所以 leetcode 上 a*a 过不了,因为它也是NFA。虽然可以转换为正则表达式 a+ 来匹配,它的构造图:

  但 a+ 的 DFA 构造图也可以是这样的:

  实际上我们写出状态转移表,然后直接查状态表效率会更高,不过我个人觉得模拟匹配的过程更有意思。

DFA 简易正则表达式匹配的更多相关文章

  1. [No0000100]正则表达式匹配解析过程分析(正则表达式匹配原理)&regexbuddy使用&正则优化

    常见正则表达式引擎引擎决定了正则表达式匹配方法及内部搜索过程,了解它至关重要的.目前主要流行引擎有:DFA,NFA两种引擎. 引擎 区别点 DFA Deterministic finite autom ...

  2. 正则表达式匹配可以更快更简单 (but is slow in Java, Perl, PHP, Python, Ruby, ...)

    source: https://swtch.com/~rsc/regexp/regexp1.html translated by trav, travmymail@gmail.com 引言 下图是两种 ...

  3. leetcode 10 Regular Expression Matching(简单正则表达式匹配)

    最近代码写的少了,而leetcode一直想做一个python,c/c++解题报告的专题,c/c++一直是我非常喜欢的,c语言编程练习的重要性体现在linux内核编程以及一些大公司算法上机的要求,pyt ...

  4. [LeetCode] Regular Expression Matching 正则表达式匹配

    Implement regular expression matching with support for '.' and '*'. '.' Matches any single character ...

  5. 正则表达式匹配/data/misc/wifi/wpa_supplicant.conf的WiFi名称与密码

    正则表达式匹配/data/misc/wifi/wpa_supplicant.conf的WiFi名称与密码: String regex_name="ssid=\"(.*?)\&quo ...

  6. 在Visual Studio中使用正则表达式匹配换行和批量替换

    系统环境:Windows 8.1 Enterprise Update 2 x64 开发环境:Mircosoft Visual Studio Ultimate 2013 Update 2 RC 问题:如 ...

  7. .NET正则表达式匹配Silverlight

    这是一个.NET正则表达式匹配工具的Silverlight 在页面中加入以下代码就可以了: <"> <param name="source" value ...

  8. Flex的正则表达式匹配速度与手工代码的比较

    flex是一个词法分析器生成器,它是编译器和解释器编程人员的常用工具之一.flex的程序主要由一系列带有指令(称为动作代码)的正则表达式组成.在匹配输入时,flex会将所有的正则表达式翻译成确定性有穷 ...

  9. Java/Js下使用正则表达式匹配嵌套Html标签

    转自:http://www.jb51.net/article/24422.htm 以前写过一篇文章讲解如何使用正则表达式完美解决Html嵌套标签的匹配问题(使用正则表达式匹配嵌套Html标签),但是里 ...

随机推荐

  1. 2019.2.21 T2题解

    meet 大概思路就是 , 找出相交的路径 , 判断方向 , 分类讨论.. 假设已经找出了相交路径 ... 若方向相同 , 则找到相交路径上边权的最大值 , 若最大值>出发时间差 , 则可行. ...

  2. 《深入理解java虚拟机》读书笔记二——第三章

    第三章 垃圾收集器与内存分配策略 1.判断对象是否已死 引用计数法: 给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1,每当引用失效时,计数器值就减1. 任何时刻计数器为0的对象就是不 ...

  3. 02-SV数据类型

    1.数据类型 内建数据类型:逻辑(logic)类型.双状态数据类型(bit,byte,shortint,int,longint).四状态数据类型(integer,time,real) 其他:定宽数组. ...

  4. IntelliJ IDEA 2019.3安装与激活(附注册码)

    转载声明:本文是根据 https://segmentfault.com/a/1190000021220727?utm_source=tag-newest 并结合个人的安装完成情况进行了改动,从而生成此 ...

  5. 论文阅读笔记(三)【AAAI2017】:Learning Heterogeneous Dictionary Pair with Feature Projection Matrix for Pedestrian Video Retrieval via Single Query Image

    Introduction (1)IVPR问题: 根据一张图片从视频中识别出行人的方法称为 image to video person re-id(IVPR) 应用: ① 通过嫌犯照片,从视频中识别出嫌 ...

  6. 网页出现横向滚动条的原因可能是使用bootstrap不当引起

    Bootstrap的栅格布局超级方便我们写网页.但是在不是全体配合使用的情况下,会出现横向滚动条的现象. 什么叫不是配合使用的情况呢? >>一种情况是:你使用了row作为你的第一层父元素: ...

  7. 剖析Javascript中sort()使用方法,以及重写sort()里的排序方法,实现自定义排序

    语法:arrayObject.sort([compareFunction]):参数compareFunction可选.规定排序顺序,必须是函数. sort() 方法用于对数组的元素进行排序,并返回数组 ...

  8. C#连接数据库时Appsettings 与connectionStrings的区别

    C#连接数据库时Appsettings 与connectionStrings的区别 转载lscyo 最后发布于2018-08-08 18:38:04 阅读数 3366  收藏 展开 一..Appset ...

  9. linux 命令 mkdir

    mkdir -p 如果要创建目录A并创建目录A的子目录B,没有用-p的情况下mkdir 逐个的创建目录(mkdir A,mkdir A/B); 如果用-p 可以直接创建2个目录 mkdir -p A/ ...

  10. JavaScript对象之get/set方法

    我们可以重写js对象属性的get和set方法. 从上图我们可以看出set和get的语法. 上图则是使用set和get方法对对象的属性进行了输入校验. 从上图可得若对象的原型链上具有不可配置的同名属性( ...