項目地址git
npm install or yarn //安裝依賴
npm run test // 運行測試文件
複製代碼
咱們將會實現一個簡單正則引擎,它的規則以下github
語法 | 含義 | example | 匹配 |
---|---|---|---|
a | 匹配文本字面量 | "a" | "a" |
* | 匹配0或多個前字符 | "a*" | "","a","aa" |
? | 匹配0或1個前字符 | "a?" | "","a" |
. | 匹配任意字符 | "." | "a","b" |
^ | 起始匹配符 | "^a" | "a","aa","ab" |
$ | 結尾匹配符 | "a$" | "aaa","bba" |
咱們用
Typescript
編寫Codetypescript
單個字符,狀況簡單的多。它有如下五種狀況:shell
/** * * @param pattern 匹配的字符 * @param char 須要被匹配的字符 * * case 1 : matchOneChar('','a')->true * case 2 : matchOneChar('a','')->false * case 3 : matchOneChar('.','b')->true * case 4 : matchOneChar('a','b')->false * case 5 : matchOneChar('a','a')->true * * 單個字符匹配有以上狀況 */
const matchOneChar =(pattern:string,char:string):boolean=>{
if(!pattern) return true; //case 1
if(!char) return false; //case 2
if(pattern === ".") return true; //case 3
return pattern === char; // case 4,5
}
複製代碼
import {search,matchOneChar} from './regex';
describe("匹配單個字符",()=>{
it("匹配字符爲空",()=>{
expect(matchOneChar('','a')).toBe(true)
});
it("匹配內容爲空",()=>{
expect(matchOneChar('a','')).toBe(false);
})
it("特殊字符 . 匹配",()=>{
expect(matchOneChar('.','a')).toBe(true);
expect(matchOneChar('.','b')).toBe(true);
})
it("匹配字符是否相同",()=>{
expect(matchOneChar('a','a')).toBe(true);
expect(matchOneChar('a','b')).toBe(false);
})
})
複製代碼
僅考慮文本匹配npm
/** * * @param pattern 匹配字符 * @param text 匹配文本 */
const match =(pattern:string,text:string):boolean=>{
if (pattern === "") return true;
if (!text) return false;
return matchOneChar(pattern[0],text[0]) &&match(pattern.slice(1),text.slice(1));
}
複製代碼
/**
*
* @param pattern 匹配字符
* @param text 匹配文本
*/
const match =(pattern:string,text:string):boolean=>{
if (pattern === "") return true;
if (pattern === "$"&& text==="") return true;
if (!text) return false;
return matchOneChar(pattern[0],text[0]) &&match(pattern.slice(1),text.slice(1));
}
複製代碼
const match =(pattern:string,text:string):boolean=>{
if (pattern === "") return true;
if (pattern === "$"&& text==="") return true;
if (!text) return false;
// 添加 「?」匹配
if (pattern[1] === '?'){
return matchOneChar(pattern[0],text[0])&&match(pattern.slice(2),text.slice(1)) || match(pattern.slice(2),text);
}
return matchOneChar(pattern[0],text[0]) &&match(pattern.slice(1),text.slice(1));
}
複製代碼
const match =(pattern:string,text:string):boolean=>{
if (pattern === "") return true;
if (pattern === "$"&& text==="") return true;
if (!text) return false;
if (pattern[1] === '?'){
return matchOneChar(pattern[0],text[0])&&match(pattern.slice(2),text.slice(1)) || match(pattern.slice(2),text);
}
if (pattern[1] === '*'){
return matchOneChar(pattern[0],text[0])&&match(pattern,text.slice(1)) || match(pattern.slice(2),text);
}
return matchOneChar(pattern[0],text[0]) &&match(pattern.slice(1),text.slice(1));
}
複製代碼
能夠經過轉換匹配符或是匹配文本轉換成頭部對齊狀況,有兩種處理方案:bash
const search =(pattern:string,text:string):boolean=>{
if (pattern[0] === '^') {
return match(pattern.slice(1), text);
} else {
return match('.*' + pattern, text);
}
}
複製代碼
const search =(pattern:string,text:string):boolean=>{
if (pattern[0] === '^') {
return match(pattern.slice(1), text);
} else {
return text.split('').some((_, index) => {
return match(pattern, text.slice(index));
});
}
}
複製代碼
思考過程由頂層開始測試
頭部不對齊 -> 頭部對齊 -> 單個字符匹配 將大的問題一步一步根據條件拆分紅小問題,如此往復。 整個實現代碼在20行左右。ui