用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;
    }

}

全部都有註釋哦。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章