项目地址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