The fool doth think he is wise, but the wise man knows himself to be a fool.
愚者總自以為聰明,智者則有自知之明。
引言
智者千慮,必有一失;愚者千慮,必有一得。在很多文字編輯器裡,正規表示式通常被用來檢索、替換那些匹配某個模式的文字。正規表示式也是前後端通吃,百無禁忌。
正規表示式中,最重要的就是萬用字元。用到的思想還是回溯演算法。
在這裡做了一個簡易版的正規表示式實現。只包含兩種萬用字元:
- * 匹配任意多個(大於等於 0 個)任意字元
- ?匹配零個或者一個任意字元
所有原始碼均已上傳至github:連結
實現
分析
- 依次考察正規表示式中的每個字元,當是非萬用字元時,就直接跟文字的字元進行匹配,如果相同,則繼續往下處理;如果不同,則回溯。
- 如果遇到特殊字元的時候,根據萬用字元來處理不同的匹配方案。如果匹配到無法匹配的時候,則進行回溯,重新選擇一種匹配方案,然後再繼續匹配剩下的字元。
初始化
/**
* 標識
*/
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
您的點贊和關注是對我最大的支援,謝謝!