We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$
^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})*$
^data:([A-Za-z-+\/]+);base64,(.+)$
*
+
?
{m,n}
[abc]
(p1|p2|p3)
"NFA not".match(/NFA|NFA not/)
NFA
NFA not
^(19|20)?[0-9]{2}[- /.](0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])$
t
o
n
i
g
nignt
(nite|knite|night)
nite
knite
night
k
lou*[bcd]*[efg]+
// TOKEN对象定义 interface TOKEN { isStart?: boolean; isEnd?: boolean; pattern: Array<string>; // 所有可能字符串 classifier: string; // 量词 * 和 + 以及 'none' next: Array<TOKEN>; } /** * 将字符串转成TOKEN序列 */ const CLASSIFIERS = ['*', '+']; function generateTOKENList(str: string): Array<TOKEN> { const length = str.length; let TOKENList: Array<TOKEN> = []; let collection = []; // []符号包裹的字符串算作一个集合 let collectionFlag = false; for (let i = 0; i < length; i++) { const char = str[i]; if (!collectionFlag) { // 不在集合匹配中 if (char === '[') { collectionFlag = true; } else { let classifier = 'none'; let nextStr = str[i + 1]; if (nextStr && CLASSIFIERS.indexOf(nextStr) > -1) { classifier = nextStr; i++; } TOKENList.push({ isStart: false, pattern: [char], classifier, next: [] }); } } else { if (char != ']') { collection.push(char); } else { collectionFlag = false; let classifier = 'none'; let nextStr = str[i + 1]; if (nextStr && CLASSIFIERS.indexOf(nextStr) > -1) { classifier = nextStr; i++; } TOKENList.push({ isStart: false, pattern: collection, classifier, next: [] }); collection = []; } } } return TOKENList; }
TOKENList
next
interface TOKEN_START { isStart: boolean; next: Array<TOKEN>; } interface TOKEN_END { isEnd: boolean; } function getNext(TOKENList: Array<TOKEN>, index: number): Array<TOKEN> { const next = []; const length = TOKENList.length; for (let i = index + 1; i < length; i ++) { const nextTOKEN = TOKENList[i]; next.push(nextTOKEN); if (nextTOKEN.classifier !== '*') { break; } } return next; } function getGenerator(TOKENList: Array<TOKEN>): TOKEN_START { let start: TOKEN_START = { isStart: true, next: [] }; let end: TOKEN_END = { isEnd: true } TOKENList.push(end as any); const length = TOKENList.length; start.next = getNext(TOKENList, -1); for (let i = 0; i < length; i++) { const currentTOKEN = TOKENList[i]; currentTOKEN.next = getNext(TOKENList, i); if (CLASSIFIERS.indexOf(currentTOKEN.classifier) > -1) { currentTOKEN.next.push(currentTOKEN); } } return start; }
function isMatch(str: string, generator: TOKEN): boolean { if (generator.isStart) { for (const nextTOKEN of generator.next) { if (isMatch(str, nextTOKEN)) return true; } return false; } else if (generator.isEnd){ return str.length ? false : true; } else { if (!str.length) { return false; } if (generator.pattern.indexOf(str[0]) === -1) { return false; } else { const restStr = str.slice(1); for (const nextTOKEN of generator.next) { if (isMatch(restStr, nextTOKEN)) return true; } return false; } } }
^
$
rex(-zeng)?$
\srex\d
\s
rex
\d
.
\.(?:com|org|net|cn|me|info)\b
.com
The text was updated successfully, but these errors were encountered:
No branches or pull requests
可能用过的正则表达式
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$
^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})*$
^data:([A-Za-z-+\/]+);base64,(.+)$
起源
引擎分类
*
,+
,?
,{m,n}
[abc]
, 多选分支(p1|p2|p3)
"NFA not".match(/NFA|NFA not/)
NFA
NFA not
前置
FA(有限自动机,又称有限状态机)
^data:([A-Za-z-+\/]+);base64,(.+)$
^(19|20)?[0-9]{2}[- /.](0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])$
DFA(Deterministic finite automaton)
t
和o
不在话下,直接能匹配上,之后就有三个备选项。文本走到n
时,它发现正则只有两个选项符合要求,经过i
走到g
的时候,只剩一个分支符合要求了。当然,还要继续匹配,然后发现,第三个分支完美符合要求。如果这时候第三个分支不是nignt
,那这次匹配就是失败了。(nite|knite|night)
时,同时比较表达式中的nite
和knite
和night
,所以会需要更多的内存。NFA(Non-deterministic finite automaton)
t
和o
也不在话下,直接都匹配上了。之后就有三个备选项,在这里就和DFA有所区别了:它不会同时去匹配多个选项,而是每一种都去尝试一下,第一个选项在t
这里停止了,接着第二个选项在k
这里也停止了。而第三个选项能完全匹配成功。(nite|knite|night)
时,NFA引擎会记录字符的位置,然后选择其中一个先匹配。(nite|knite|night)
时,比较nite
后发现不匹配,于是NFA引擎换表达式的另一个分支knite
,同时文本位置回溯,重新匹配字符'night'。这也是NFA引擎是非确定型的原因,同时带来另一个问题效率可能没有DFA引擎高。回溯
回溯的两个要点
DFA和NFA对比
实现简单引擎
规则介绍
lou*[bcd]*[efg]+
思路
lou*[bcd]*[efg]+
就可以按照以下划分生成一个TOKEN序列TOKENList
数组加入起始状态和结束状态。之后我们给起始状态的next
初始化,再循环遍历数组,为数组的每一项的next
初始化,这样就通过next
中存储的指针将自动机的各个状态串联起来了。优化
^
,引擎会只从字符串开始进行尝试,而不去尝试其它的位置(减少搜索的初始状态);$
并且没有+
、*
这种可以无限重复的量词,正则引擎会尝试从末尾的倒数若干字符进行尝试,例如rex(-zeng)?$
最多匹配 8 个字符,因此引擎会从倒数第八个字符开始尝试(减少搜索的初始状态);\srex\d
只有三个元素:\s
、rex
、\d
(减少递归层数);.
,特定的量词代替`*`。这样能减少很多不必要的遍历。\.(?:com|org|net|cn|me|info)\b
,因为更多的域名是.com
的,引擎在更多的情况下第一次尝试就可以匹配到结果。学习资料
The text was updated successfully, but these errors were encountered: