看了一些高评论的博客,看起来都是很高深,我也写个看起来高深的。
用NFA实现正则表达式匹配,需要的类,有向图和有向图的深度遍历。下面NFA的实现。
package stringFind;
import digraph.Digraph;
import digraph.DirectDFS;
import simpleStructure.Bag;
import simpleStructure.Stack2;
/**
* 用NFA搜索一个String是不是符合一个正则表达式,只支持大写字母
* @author Administrator
*
*/
public class NFA
{
private class Item
{
public int index;
public char c;
public Item(int i, char c)
{
this.index = i;
this.c = c;
}
}
private char[] re;//用来保存正则表达式,正则表达式的每一个字符都是一个状态
private Stack2<Item> stack;//用来放入左括号,或者符号
private Digraph digraph;//存放由空边构成的有向图
public NFA(String regularExpression)
{
this.re = regularExpression.toCharArray();
stack = new Stack2<>();
digraph = new Digraph(re.length);
createNFA();
}
/**
* 创建NFA
*/
private void createNFA()
{
Item lastBracket = null;// 栈里面的上一个左括号
Item lastOr = null;// 栈里面的'|'
//遍历正则表达式中的每一个字符,构造NFA,用digraph保存空边转换,re[]保存字母匹配转换
for (int i = 0; i < re.length; i++)
{
char c = re[i];
int charNum = c;
//如果是字母A-Z的话就跳过,下一个字符
if (charNum >= 65 && charNum <= 90)
continue;
//不是字母A-Z的话并且不是'|'的话就加一条指向下一个状态的空边
else if (i + 1 < re.length && (char)charNum!='|')//'|'后面不加连到下一个节点的连接
digraph.addEdge(i, i + 1);
//如果是'('或者是'|'就压入栈,下一个字符
if (c == '(' || c == '|')
{
stack.push(new Item(i, c));
continue;
}
//如果是')'判断栈里面弹出的第一个元素是不是'('是的话就弹出
//不是的话就应该是'|',这种情况添加两条空边
if (c == ')')
{
Item item = stack.pop();
if (item.c == '(')
lastBracket = item;
else
{
lastOr = item;
lastBracket = stack.pop();
digraph.addEdge(lastBracket.index, lastOr.index + 1);
digraph.addEdge(lastOr.index, i);
}
continue;
}
//判断是不是'*',再判断上一个字符是不是')',根据不同情况添加两条空边
if (c == '*')
{
if (re[i - 1] == ')')
{
digraph.addEdge(i, lastBracket.index);
digraph.addEdge(lastBracket.index, i);
} else
{
digraph.addEdge(i, i - 1);
digraph.addEdge(i - 1, i);
}
}
}
}
public boolean search(String txt)
{
// 构造初始状态集,从0状态开始,得到bag中的初始状态集
int stateNum = re.length;
Bag<Integer> bag = new Bag<>();
bag.add(0);
DirectDFS dfs = new DirectDFS(digraph, bag);
for (int i = 0; i < stateNum; i++)
{
if (dfs.marked(i))
if (!bag.contain(i))
bag.add(i);
}
// 遍历txt中所有字符
for (int i = 0; i < txt.length(); i++)
{
// 读一个字符,对bag中每一个状态进行状态转换,返回新的bag
bag = readchar(txt.charAt(i), bag);
// 求bag中状态在digraph中的闭包
dfs = new DirectDFS(digraph, bag);
for (int j = 0; j < stateNum; j++)
{
if (dfs.marked(j))
if (!bag.contain(j))
bag.add(j);
}
}
// 查找最终bag中有没有终止状态
if(bag.contain(re.length - 1))return true;
return false;
}
private Bag<Integer> readchar(char c, Bag<Integer> bag)
{
Bag<Integer> newBag = new Bag<>();
//对bag中的每一个状态,与字符c进行匹配,如果匹配,就将新状态加入newBag
for (int stateNum : bag)
{
int stateCharNum = re[stateNum];
char stateChar = (char) stateCharNum;
if (stateChar == '.' || stateCharNum == c)
newBag.add(stateNum + 1);
}
return newBag;
}
}
全部都有注释哦。。