Algs4_5.4 Regular Expressions

非确定有限状态自动机

当且仅当一个NFA从状态0开始从头读去了一段文本中的所有字符,进行了一系列状态转换,并最终到达了接受状态时,则称该NFA识别了一个文本字符串。

5 模拟NFA的运行

5.1 自动机的表示

char数组re[]表示正则表达式本身,也表达了匹配转换。使用有向图 G 表示所有不读取字符的转换(ϵ-转换)

5.2 NFA的模拟与可达性

纪录自动机在检查当前输入字符时可能遇到的所有状态的集合。关键点在于解决多点可达性的问题。查找所有从状态 0 出发经过ϵ 转换可达的所有状态的集合,对于所有状态检查起是否可能与第一个字符匹配, 匹配后就得到了起在匹配第一个字符之后可能达到的状态集合。

Proposition Q. 判定一个长度为 M 的正则表达式所对应的NFA能否识别一段长度为N的文本所需的时间在最坏情况下和 MN 成正比。

下面这段代码即为NFA的简单构造和匹配过程,还有一些正则表达式的功能需要补全。

package algs4.strings.re;
import java.util.Stack;

import edu.princeton.cs.algs4.Bag;
import edu.princeton.cs.algs4.Digraph;
import edu.princeton.cs.algs4.DirectedDFS;
import edu.princeton.cs.introcs.*;

class NFA {
    private int M;
    private Digraph G;
    private char[] re;

    public NFA(String regexp){
        re =regexp.toCharArray();
        M = re.length;
        G = new Digraph(M + 1);
        Stack<Integer> stk = new Stack<Integer>();

        for( int i = 0; i < M; i++){
            int lp = i;
            if      (re[i] == '(' || re[i] == '|')
                stk.push(i);
            else if (re[i] == ')'){
                int or = stk.pop();
                if(or == '|'){//Suppose there's only one '|' in a parentheses
                    lp = stk.pop();
                    G.addEdge(lp, or + 1);
                    G.addEdge(or, i);
                }
                else lp = or;
            }
            if      (i < M - 1 && re[i + 1] == '*'){
                G.addEdge(lp,i+1);
                G.addEdge(i+1, lp);
            }
            if      (re[i] == '(' || re[i] ==')' || re[i] == '*')
                G.addEdge(i, i+1);
        }
    }

    public boolean recognies(String txt){
        Bag<Integer> bag = new Bag<Integer>();
        DirectedDFS dfs = new DirectedDFS(G, 0);
        for(int i = 0; i < G.V(); i++){
            if(dfs.marked(i) ) bag.add(i);
        }
        for(int i = 0; i < txt.length(); i++){
            Bag<Integer> match = new Bag<Integer>();
            for(int v: bag)
                if(v < M)
                    if(re[v] == txt.charAt(i) || re[v] == '.')
                        match.add(v + 1);

            bag = new Bag<Integer>();
            dfs = new DirectedDFS(G,match);
            for( int v = 0; v < G.V(); v ++){
                if(dfs.marked(v)) bag.add(v);
            }
            for(int v: bag) if(v == M) return true;
        }

        return false;
    }

    public static void main(String[] args) {
        String txt = StdIn.readString();
        String re = StdIn.readString();
        NFA nfa = new NFA(re);
        StdOut.println(nfa.recognies(txt));
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值