用NFA实现正则表达式匹配(java代码)

看了一些高评论的博客,看起来都是很高深,我也写个看起来高深的。
用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;
    }

}

全部都有注释哦。。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理中的正则表达式NFA(非确定有限自动机)的转换是将一个正则表达式转换成等价的、描述相同语言的NFA的过程。 在转换过程中,首先需要定义正则表达式的基本操作,包括连接、选择和闭包三种。然后,根据这些基本操作,通过递归的方式将正则表达式转换为NFA。 具体过程如下: 1. 基础操作: - 连接:对于正则表达式r1、r2,连接操作将其转换为一个新的NFA,该NFA包含r1和r2的所有状态,并且r1的终止状态的空转移边指向r2的起始状态。 - 选择:对于正则表达式r1、r2,选择操作将其转换为一个新的NFA,该NFA包含r1和r2的所有状态,并且新增加一个起始状态和一个终止状态,起始状态通过空转移边分别指向r1和r2的起始状态,而r1和r2的终止状态通过空转移边指向新的终止状态。 - 闭包:对于正则表达式r,闭包操作将其转换为一个新的NFA,该NFA包含r的所有状态,并且新增加一个起始状态和一个终止状态,起始状态通过空转移边指向r的起始状态,而r的终止状态通过空转移边分别指向起始状态和新的终止状态。 2. 利用基本操作将正则表达式转换为NFA的过程: - 将正则表达式转换为后缀表达式。 - 利用后缀表达式构建NFA的过程中,可以使用栈来辅助计算。 - 遍历后缀表达式的每一个字符: - 如果是操作数,则将其转换为NFA,并将其入栈。 - 如果是操作符,则从栈中弹出相应数量的NFA,按照该操作符进行基本操作,并将结果NFA入栈。 - 最终栈中只剩下一个NFA,即为转换结果。 通过上述过程,就可以将正则表达式转换为NFA代码形式。根据具体的编程语言和编译器实现,可以将其转换为相应的数据结构和算法,从而实现正则表达式的匹配和其他操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值