NFA
任意正则表达式都存在一个与之对应的NFA,反之亦然.
正则表达式 ((A*B|AC)D)对应的NFA(有向图), 其中红线对应的为该状态的ε转换, 黑线表示匹配转换

我们定义的NFA具有以下特点:
- 正则表达式中的每个字符在NFA中都有且只有一个对应状态,NFA的其实状态为0,并包含一个虚拟的接收状态
- 正则表达式中的字母所对应的状态都有一条从它指出的黑色的边,并且一个状态只能有一条指出的黑色边
- 正则表达式中的元字符所对应的状态至少含有一条指出的红色的边
ε转换
不需要扫描匹配文本中的任意字符,自动机就可以从一个状态转换到另一状态
使用 NFA模拟匹配过程:
- 首先获取初始状态通过ε转换可以到达的所有状态集合,上图为0,1,2,3,4,6
- 顺序扫描匹配文本中的字符,如果状态集合中找到匹配该字符的状态(可以使多个),自动机就可以扫过该字符并由黑色的边转到下一个状态,这种转换成为匹配转换,由下一状态及下一状态的的ε转换生成新的状态集合,继续扫描下一个字符
- 扫描完所有字符后,如果最终到达的所有状态中包含接受状态,则匹配该字符串

源代码namespace NFA
{
public class IntList : List<int>
{
} public class Digraph
{
public int E { get; set; }
public int V { get; set; }
public IntList[] Adjs { get; set; } public Digraph(int v)
{
this.V = v;
this.E = 0;
Adjs = new IntList[v];
for (int i = 0; i < v; i++)
{
Adjs[i] = new IntList();
}
} public void AddEdge(int from, int to)
{
Adjs[from].Add(to);
E++;
} public IntList Adj(int index)
{
return Adjs[index];
}
} public class DirectedDFS
{
public bool[] Marked;
public DirectedDFS(Digraph g, int s)
{
Marked = new bool[g.V];
Dfs(g, 0);
} public DirectedDFS(Digraph g, List<int> source)
{
Marked = new bool[g.V];
source.ForEach(x =>
{
if (!Marked[x])
{
Dfs(g, x);
}
});
} public void Dfs(Digraph g, int v)
{
Marked[v] = true;
g.Adjs[v].ForEach(x =>
{
if (!Marked[x])
{
Dfs(g, x);
}
});
}
}
} namespace NFA
{
public class NFA
{
private string regex;
//NFA的ε转换有向图
private Digraph G; public NFA(string reg)
{
this.regex = reg;
Stack<int> ops = new Stack<int>();
int M = regex.Length;
G = new Digraph(M+1);
//循环状态
for (int i = 0; i < M; i++)
{
int lp = i;
if (regex[i] == '(' || regex[i] == '|')
{
ops.Push(i);
}
else if (regex[i] == ')')
{
int or = ops.Pop();
if (regex[or] == '|')
{
lp = ops.Pop();
G.AddEdge(lp, or + 1);
G.AddEdge(or, i);
}
else
{
lp = or;
}
}
if(i<M-1 && regex[i+1] == '*')
{
G.AddEdge(lp,i+1);
G.AddEdge(i + 1, lp);
}
if (regex[i] == '(' || regex[i] == '*' || regex[i] == ')')
{
G.AddEdge(i, i + 1);
}
}
} public bool Recognize(string txt)
{
List<int> pc = new List<int>();
DirectedDFS dfs = new DirectedDFS(G, 0); for (int i = 0; i < G.V; i++)
{
if (dfs.Marked[i])
{
pc.Add(i);
}
} for (int i = 0; i < txt.Length; i++)
{
List<int> match = new List<int>();
foreach (int v in pc)
{
if (v < regex.Length)
{
if (regex[v] == txt[i] || regex[v] == '.')
{
match.Add(v + 1);
}
}
}
pc = new List<int>();
dfs = new DirectedDFS(G, match); for (int v = 0; v < G.V; v++)
{
if (dfs.Marked[v])
{
pc.Add(v);
}
}
}
foreach (int v in pc)
{
if (v == regex.Length)
{
return true;
}
}
return false;
}
}
}
NFA的更多相关文章
- NFA转DFA - json数字识别
json的主页上,提供了number类型的符号识别过程,如下: 图片引用:http://www.json.org/json-zh.html 实际上这张图片表示的是一个状态机,只是状态没有标出来.因为这 ...
- 求子串-KPM模式匹配-NFA/DFA
求子串 数据结构中对串的5种最小操作子集:串赋值,串比较,求串长,串连接,求子串,其他操作均可在该子集上实现 数据结构中串的模式匹配 KPM模式匹配算法 基本的模式匹配算法 //求字串subStrin ...
- NFA引擎匹配原理
1 为什么要了解引擎匹配原理 一个个音符杂乱无章的组合在一起,弹奏出的或许就是噪音,同样的音符经过作曲家的手,就可以谱出非常动听的乐曲,一个演奏者同样可以照着乐谱奏出动听的乐曲,但他/她或 ...
- 编译系统中的 NFA/DFA算法理解
1.问题概述 NFA 和 DFA浅析---要深入了解正则表达式,必须首先理解有穷自动机. 有穷自动机(Finite Automate)是用来模拟实物系统的数学模型,它包括如下五个部分: 有穷状态集St ...
- C# 词法分析器(四)构造 NFA
系列导航 (一)词法分析介绍 (二)输入缓冲和代码定位 (三)正则表达式 (四)构造 NFA (五)转换 DFA (六)构造词法分析器 (七)总结 有了上一节中得到的正则表达式,那么就可以用来构造 N ...
- nfa转dfa,正式完成
为了加速转换的处理,我压缩了符号表.具体算法参考任何一本与编译或者自动机相关的书籍. 这里的核心问题是处理传递性闭包,transitive closure,这个我目前采取的是最简单的warshall算 ...
- 正则转nfa:完成
太累了,感觉不会再爱了.问题已经解决,具体的懒得说了. #include "regular_preprocess.h" //这个版本终于要上nfa了,好兴奋啊 //由于连个节点之间 ...
- 正则转nfa:bug消除
正则到nfabug的解决方法 前面提到了这个bug,为了解决这个bug,我们必须在每次引用到一个假名的时候,都构建一个拷贝.现在假设我们遇到了一个假名,并得到了他的开始节点和结束节点,当前的难题就是构 ...
- 正则转nfa:bug出现。
本人写的一个正则到nfa的bug 刚写完前面的那篇,自己用脑子过了一下,发现了一个bug.具体情况如下. 这个bug的产生条件是多次调用假名的时候,每次调用都会修改假名的nfa图.直接这么说不好理解, ...
- 最初步的正则表达式引擎:nfa的转换规则。
[在此处输入文章标题] 正则到nfa 前言 在写代码的过程中,本来还想根据龙书上的说明来实现re到nfa的转换.可是写代码的时候发现,根据课本来会生成很多的无用过渡节点和空转换边,需要许多的代码.为了 ...
随机推荐
- sql 查询替换字符
Select A,B,C from Tb1 –查询所有 Select A,replace(B,’1’,’壹’),C from Tb1 替换查询 Tb1 A B C AA1 1 CC A ...
- 三种“BIOS设置光驱第一启动的图解”
除特殊机器类型一般都是“开机按DEL进入BIOS界面,当然还有AMD主板有按F2的进入” 第一种.AWARD BIOS设置光驱启动方法: 进入Bios界面,选第二项——>回车 选中此项,按PAG ...
- 团体程序设计天梯赛-练习集-L1-047. 装睡
L1-047. 装睡 你永远叫不醒一个装睡的人 —— 但是通过分析一个人的呼吸频率和脉搏,你可以发现谁在装睡!医生告诉我们,正常人睡眠时的呼吸频率是每分钟15-20次,脉搏是每分钟50-70次.下面给 ...
- Lua操作系统库、流、文件库
Lua操作系统库.流.文件库 1.Lua中所有的操作系统库函数 (1)os.clock() --功能:返回执行该程序cpu花费的时钟秒数 (2)os.time(...) --按参数的内容返回一个时间值 ...
- HDU 2267 How Many People Can Survive(广搜,简单)
题目 //一道简单的广搜水题 #include<queue> #include<stdio.h> #include<string.h> #include<al ...
- CentOS 7.2.1511编译安装Nginx1.10.1+MySQL5.7.15+PHP7.0.11
准备篇 一.防火墙配置 CentOS 7.2默认使用的是firewall作为防火墙,这里改为iptables防火墙. 1.关闭firewall: systemctl stop firewalld.se ...
- HashMap源码分析笔记(一)
一.结构 HashMap的结构由数组和链表组成,可以说是一个链表类型的数组: 快速定位方式:key值得hash变换作为数组索引快速找到对应数组块,之后通过hash值对比从链表中查找到匹配项. hash ...
- python爬虫05 | 年轻人,不会正则表达式你睡得着觉?有点出息没有?
现在 你已经会使用 python 模拟浏览器 进行一些 Http 的请求了 那么请求完之后 服务器返回给我们一堆源代码 我们可不是啥都要的啊 我们是有原则的 我们想要的东西 怎么能一股脑的啥都往自己兜 ...
- HDU 2415 Bribing FIPA
Bribing FIPA Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original I ...
- 洛谷 P3178 BZOJ 4034 [HAOI2015]树上操作
题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...