[查漏補缺]正規表示式匹配演算法

弒曉風發表於2019-04-01
The fool doth think he is wise, but the wise man knows himself to be a fool. 
愚者總自以為聰明,智者則有自知之明。

引言

智者千慮,必有一失;愚者千慮,必有一得。在很多文字編輯器裡,正規表示式通常被用來檢索、替換那些匹配某個模式的文字。正規表示式也是前後端通吃,百無禁忌。

正規表示式中,最重要的就是萬用字元。用到的思想還是回溯演算法。

在這裡做了一個簡易版的正規表示式實現。只包含兩種萬用字元:

  • * 匹配任意多個(大於等於 0 個)任意字元
  • ?匹配零個或者一個任意字元

所有原始碼均已上傳至github:連結

實現

分析

  1. 依次考察正規表示式中的每個字元,當是非萬用字元時,就直接跟文字的字元進行匹配,如果相同,則繼續往下處理;如果不同,則回溯。
  2. 如果遇到特殊字元的時候,根據萬用字元來處理不同的匹配方案。如果匹配到無法匹配的時候,則進行回溯,重新選擇一種匹配方案,然後再繼續匹配剩下的字元。

初始化

    /**
     * 標識
     */
    private boolean match;
    /**
     * 正規表示式
     */
    private char[] patChars;
    /**
     * 長度
     */
    private int plen;

    /**
     * 初始化
     *
     * @param patten 正規表示式
     */
    private Pattern(String patten) {
        patChars = patten.toCharArray();
        this.plen = patChars.length;
        match = false;
    }複製程式碼

匹配

    private boolean isMatch(String txt) {
        match = false;
        char[] txtChars = txt.toCharArray();
        int tlen = txtChars.length;
        recursiveMatch(0, 0, txtChars, tlen);
        return match;
    }複製程式碼

回溯演算法

這裡其實就是一個大型的if-else,判斷符合哪一種情況,然後進行遞迴。如果再加幾種情況,也就是多加一個if-else,這樣的話if-else巢狀層級太多,可以考慮使用switch或者使用設計模式,這是後話,暫且不提。

    private void recursiveMatch(int ti, int pj, char[] txtChars, int tlen) {
        if (match) return;
        if (pj == plen) {
            if (ti == tlen) match = true;
            return;
        }

        if (patChars[pj] == '*') {//* 任意字元
            for (int i = 0; i < tlen - ti; i++) {
                recursiveMatch(ti + i, pj + 1, txtChars, tlen);
            }
        } else if (patChars[pj] == '?') {//? 0 or 1
            recursiveMatch(ti, pj + 1, txtChars, tlen);
            recursiveMatch(ti + 1, pj + 1, txtChars, tlen);
        } else if (ti < tlen && patChars[pj] == txtChars[ti]) {
            recursiveMatch(ti + 1, pj + 1, txtChars, tlen);
        }
    }複製程式碼

測試程式碼

    public static void main(String[] args) {
        String patten = "*@c?.com";
        Pattern pattern = new Pattern(patten);
        String txtT = "666@cc.com";
        boolean resT = pattern.isMatch(txtT);
        System.out.println(txtT + "的匹配結果:"  + resT);
        String txtF = "666@c.con";
        boolean resF = pattern.isMatch(txtF);
        System.out.println(txtF + "的匹配結果:"  + resF);
    }複製程式碼

測試結果

[查漏補缺]正規表示式匹配演算法

常用的正規表示式

匹配網站

/((ht|f)tp(s)?:)?(\/\/*)?(w{3}.*)?[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/g

其他:傳送門

end

[查漏補缺]正規表示式匹配演算法

您的點贊和關注是對我最大的支援,謝謝!


相關文章