正则表达式


正则表达式

对于任意正则表达式都存在一个与之对应的非确定有限状态自动机(NFA),反之亦然

1.正则匹配

/**
 * 正则表达式的模式匹配
 * 概述: 每个正则表达式都对应一个NFA,反之亦然
 * 思路: 将正则表达式转换为有向图(仅将元字符"(*|)"转换为可直接比较的特定字符),这样就可以直接对字符进行匹配
 */
public class NFA {
    private DiGraph graph; //有向图
    private String regexp; //正则表达式
    private final int m;   //正则表达式字符数

    public NFA(String regexp) {
        this.regexp = regexp; //正则表达式
        this.m = regexp.length(); //长度
        this.graph = new DiGraph(m+1); //0-m状态, m为终态
        ArrayDeque<Integer> ops = new ArrayDeque<>(); //使用栈进行括号匹配,遇到'('入栈,遇到')'出栈
        for(int i=0;i<m;++i){
            int lp = i;
            char ch = regexp.charAt(i);
            if(ch == '(' || ch == '|') ops.push(i);
            else if(ch == ')'){
                int or = ops.pop();
                if(regexp.charAt(or) == '|'){ //处理或| ,只能处理单个|(改进:直接处理? 额外加上括号?)
                    graph.addEdge(or,i);
                    lp = ops.pop();
                    graph.addEdge(lp,or+1);
                }
                else if(regexp.charAt(or) == '(')
                    lp = or;
            }
            if(i<m-1 && regexp.charAt(i+1) == '*'){ //处理闭包*,返回到本身或者进入下一个状态
                graph.addEdge(lp,i+1);
                graph.addEdge(i+1,lp);
            }

            if(ch == '(' || ch == '*' || ch == ')') //处理元字符(不能直接比较,将其转换到特定的可比较的字符)
                graph.addEdge(i,i+1);
        }
        if(!ops.isEmpty()) throw new RuntimeException("格式不支持");
    }

    //整个txt和regexp是否完全匹配(通过有向图可达性(到达特定字符),计算出当前状态所有可能匹配情况)
    public boolean recognizes(String txt){
        DirectedDFS dfs = new DirectedDFS(graph,0); //有向图深度优先搜索计算可达性
        HashSet<Integer> current = new HashSet<>();
        HashSet<Integer> match = new HashSet<>();
        for(int i=0;i<txt.length();++i){
            for(int v=0;v<graph.V();++v)
                if(dfs.marked(v)) current.add(v); //所有可达的特定字符

            char ch = txt.charAt(i);
            if("()*|".indexOf(ch) != -1) throw new RuntimeException("txt中不能包含元字符: "+ch);
            for(int v: current){    //匹配所有可能情况
                if(v == m) continue;
                if(ch == regexp.charAt(v) || ch == '.')
                    match.add(v+1);
            }
            if(match.isEmpty()) return false; //不可达
            dfs = new DirectedDFS(graph,match); //深度优先搜索,所有当前匹配的状态match集合可达的下一特定字符

            current.clear();
            match.clear();
        }
        for(int v=0;v<graph.V();++v) //匹配到结尾,是否可达终态
            if(dfs.marked(v) && v == m) return true;
        return false;
    }
}

文章作者: Bryson
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Bryson !
评论
 上一篇
数据压缩 数据压缩
数据压缩 在此主要介绍使用Huffman编码压缩和LZW压缩算法 地址: 整合为JUI程序(Java 8+) 1.Huffman压缩(霍夫曼压缩)1.1.BitBuffer辅助类 - 按bit位处理字节数组/** * BitterBuf
2019-07-30
下一篇 
子字符串查找 子字符串查找
子字符串查找 给定一段长度为n的文本txt和一个长度为m的pattern模式串,在文本中找到和该模式匹配的字串 1.BruteForce算法(暴力子字符串查找算法)/** * 暴力子字符串查找: * 时间复杂度: 一般情况1.1N
2019-07-15
  目录