8000 GitHub - libertyzhao/mini-regexp: js写的一个正则引擎,构建dfa查找
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

libertyzhao/mini-regexp

Repository files navigation

正则的词法分析程序

自底向上,由简单到复杂,由具体到抽象

目前通过nfa转dfa形成二维数组的邻接表,然后通过邻接表来判定字符串是否符合正则规则

目前支持闭包(?+*),字符集([a-z]),点,字符,括号,或,转义符

输入公式:(123\\.[a-z])
宏替换后:(123\\.[a-z])
输入字符串:123.c
通过


输入公式:([0-9]\\.[a-z])+
宏替换后:([0-9]\\.[a-z])+
输入字符串:ab.cd
不通过


输入公式:[0-9]\\.[a-z]+
宏替换后:[0-9]\\.[a-z]+
输入字符串:1.abcd
通过


输入公式:([0-9]|[a-z])+
宏替换后:([0-9]|[a-z])+
输入字符串:abc000d
通过

Thompson 构造法

ℇ 代表一种特殊的字符,表示不需要任何输入,就可以从当前状态进入下个状态。

通过Thompson构造法产生的状态机有如下特点:

  1. 状态机一定只有一个初始状态节点和一个结束状态节点。
  2. 任何一个状态,最多只有两条出去的转换边。
  3. 每个状态节点所拥有的边最多只有三种可能:

(1) 有一条边对应的是单个输入字符

(2) 有一条边,对应的是ε

(3) 有两条出去的边,对应的都是ε

大概梳理一下逻辑

  • input,负责接收字符串,然后给lexer提供字符

input负责提供字符给lexer,里面可以处理和字符有关的部分,比如直接提供一个单词给lexer或者直接提供一个字符给lexer,还可以处理字符串的来源,从文件里读取,或者从传参读取等,这可以让lexer更专心的做词法判定方面的事情,提供尽量简单的接口给lexer。

  • lexer,负责从input里面拿字符,根据词法规则,给出相应的词法类型

负责定义一串词法规则,然后通过input里提供的字符,去判定当前字符属于哪个词法规则,只提供简单的match方法和advance方法,match用于判断当前字符属于哪个词法规则,advance用于移动到下一个字符。

  • parser,通过lexer给出的词法类型,去比对是否符合当前的语法规则,然后通过Nfa的数据结构去构建一个图

负责定义一串语法规则,目前处理方案是,一个语法规则其实就是一个方法,每个方法里面做相应的语法制导操作,比如:[a-z],这种是可以输入a-z里面任意字符,则先生成一个Nfa节点,然后节点可以有a到z条边,先匹配[,然后获取里面的字符串,然后匹配到],则正面该语法匹配完毕。

先从细粒度最小的非抽象语法规则开始,比如正则里面的匹配,其实主要是:字符集[a-z],任意字符.,单个字符b。先构建这种最小的语法单位,然后再往上就是闭包,拿字符集举例子就是:[a-z]*,匹配到]之后,再看看后面是不是*,如果是就进行闭包的语法制导。

里面所有的语法规则,都会构建出一个点A和若干条边bcd,可以理解为从状态点A,接收到bcd这种字符的时候,可以转移到另外一个状态点。构建了许多个点ABCD以后,ABCD之间通过各种边连接,就形成了一个网状的图。

  • Nfa,是一个Nfa的节点,里面包括指向其他节点的边,和存储的字符集等一些属性

节点的数据结构,上面保存着它指向的另外的节点,保存着它的边上可以承载的字符集,也可以通过epsilon边直接平移到另外的节点上(主要是因为闭包的选择逻辑,即可以有也可以没有的情况,这种直接拆分成两个点处理)

  • NfaPair, 5861 造一个图,有一个起点和终点,然后中间通过各种边的延伸,形成一个图。
  • Dfa,是一个Dfa的节点,将Nfa转Dfa,其实就是讲Nfa节点集合当做一个Dfa节点

这里是将Nfa节点集合,识别成一个DFA节点,然后将Nfa节点集合里面所有能接受的输入都拿出来,指向下一个新的Nfa节点,然后把新Nfa节点的集合又拿出来做一个DFA节点,然后把这个集合的输入又拿出来,指向下一个新DFA节点,循环,直到所有dfa节点的边都已经实现了。这样就用二维数组构成了一个图。

  • NfaManage,是一个类似池的概念,所有的nfa节点从这个池子里面捞取,会初始化一些节点
  • NfaMachine,控制器,控制其他部件的操作,比如控制parser的解析,然后nfa转dfa形成二维数组的有向图,是一个容器,然后里面控制各种其他部件的操作。
  • TableProcess,是一个table的加工的地方,通过子集构造法,把NfaPair转换成dfa,然后用dfa最小化算法来最小化dfa。
  • PreProcess,正则之前的一个预处理操作,现在只做了宏替换,比如 D [0-9], 那么久就会把正则中的 {D} 替换成[0-9]。
  • Print,用来打印NfaPair构成的图

附上一个 a | b 的NFA图

         a        
--->  2 -----> 3 ---
|                  |
|                  
1                  4
|                  
|                  |
---> 5  -----> 6 ---
         b        

 从状态1,经过一个选择a|b,所以直接拆分成两个节点2和5,通过ℇ直接平移到状态2和5,然后进行相应的a或者b的输入,则再移动到状态3或者6,然后再通过ℇ,移动到4。

输入一个正则表达式,然后一个字符一个字符的解析,通过lexer拿到该字符的type,然后进入parser进行语法解析,构成一个类似语法树(nfaPair)概念的东西,然后tableProcess通过加工这棵语法树,构成了一个dfa的图,然后压缩这个dfa。

About

js写的一个正则引擎,构建dfa查找

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published
0