DFA在编译过程中起到了分析语法的作用,同理,敏感词过滤和正则表达式同样可以使用DFA实现
实际使用中,正则表达式可以通过:正则->NFA->DFA->最简DFA
希望使用DFA能够解决H248的digitMap匹配原则;

正则->NFA

这部分有三个替换原则如下:

  1. 规则一,r=ab(就是a&b),状态转换如下:i(起始状态)->(a)->k(中间状态)->(b)->j(结束状态)
  2. 规则二,r=a|b,转换状态如下:i(起始状态)->(a)->j(结束状态);第二条路:i(起始状态)->(b)->j(结束状态)
  3. 规则三,r=a*(通配符)转换状态如下:i(起始状态)->(只要能达到下一个状态即可的路径)->k(中间状态)->(只要是能达到下一个状态即可的路径)->j(结束状态)
  4. 这个分解过程要持续进行到只剩下epsilon和单纯的字符
  5. (对于digitmap来说就是分解到剩下x*#0-9和epsilon这几种情况)

    NFA->DFA

    子集构造法:使用一个表格构造子集;

  6. 第一行第一列的内容记作I;从起点开始,经过任意ε(包含经过0个),可以到达的结点的集合;

  7. 第一行第二列的内容记作Ia;表示,从该集合开始,经过一个a可以到达的节点的集合;所谓经过一个a的意思是 只能经过一个a,经过2个a的不算,经过的ε不算,epsilon随便经过,经过几个都可以
  8. 第一行第三列的内容记作Ib;表示,从该集合的起点开始,只经过一个b可以达到的节点的结合;同样,要求是经过且只经过一个b,对epsilon不做限制,限制b和epsilon之外的一切的路径;
  9. ……如果nfa经过简化之后包含有更多的路径,则继续向下写;

此时状态表如下

i ia ib
从起点出发,经过epsilon得到的子集,记作子集A 以子集A中的元素为起点,分析a边推出的子集;记作子集B 以子集A中的元素为起点,分析b边推出的子集;记作子集C
子集B 以子集B中的元素为起点,分析a边推出的子集…假设这里是状态B 以子集B中的元素为起点,分析b边推出的子集;假设为子集D
etc…. ….. ……
  1. 这样不断分析下去,子集的数量总是有限的,当再也找不出新的子集写到第一列中被分析,那么所有的子就完全被列出了;
  2. 然后可以构建DFA:从第一行开始一行一行的进行构建;从第一行可以构建出子集A经过a可以到达子集B,子集A经过b可以到达子集C;就这样一行一行的写出来

    DFA的简化

    假设当前存在ABCDE几个子集,进行切分,切分的规则如下

  3. I,I发出的边数相同

  4. I,I发出的边相同
  5. 对应相同的边连接的状态属于同一个等价类

对于包含终态的子集来讲,第一步就会把这些包含终态的子集切分出来;然后对余下的子集的集合进行切分

DigitMap的构建

Q1.是否同时存在复数个DigitMap规则?

应当是存在的;as follow

  1. //1. 规则1:本地电话匹配
  2. [2-8]xxxxxxx
  3. //2. 规则2:特殊服务号码
  4. 10xxS.|11[02479]|11[13568]Sx.|12[026789]|121xx|12[3-5]Sx.|168xxxxx|1[79]xSx.|18xSx|200|201|20[2-9]xSx|400xS.|444S.|600x|800xxxxxxx|9xxxxSx.

如果一个号码拨入,依次进行match;以上面的例子来讲,如果1的匹配级别高于2的匹配级别,则使用规则1;否则使用规则2;

Q2.如何划分状态?

As follow

  1. //1. 规则1:本地电话匹配
  2. [2-8]xxxxxxx
  3. //2. 规则2:特殊服务号码
  4. 10xxS.|11[02479]|11[13568]Sx.|12[026789]|121xx|12[3-5]Sx.|168xxxxx|1[79]xSx.|18xSx|200|201|20[2-9]xSx|400xS.|444S.|600x|800xxxxxxx|9xxxxSx.

如果现在要针对规则1生成DFA应当如何实现??

  1. 将[2-8]xxxxxxx作为一个正规表达式输入程序
  2. 使用Tompson算法输出NFA
  3. 使用子集构造算法输出DFA
  4. 使用hopcroft算法简化DFA

    Q3.正则表达式和DigitMap string部分内容的映射

    从RE到NFA匹配存在三条原则,&,|,*;

  5. DigitMap中如果出现了准确的数字,则视为&;

  6. DigitMap中如果出现了[]或者x,则视为|;
  7. DigitMap中如果出现了 . ,则视为*;