任意正则表达式都存在一个与之对应的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; } } }
时间: 2025-01-16 01:15:38