正则转nfa:bug消除
正则到nfabug的解决方法
前面提到了这个bug,为了解决这个bug,我们必须在每次引用到一个假名的时候,都构建一个拷贝。现在假设我们遇到了一个假名,并得到了他的开始节点和结束节点,当前的难题就是构造这个假名所代表的nfa的副本。构造方法类似于子集构造法,我们设立一个集合,这个集合为R,集合中的每个元素都有一个标志位为访问位。初始化R为开始节点a,并让他的访问位为0。现在开始进入迭代,只要R中存在访问位为0的点,将他的访问位改为1,然后将他的邻接表中的点都加入到R中。加入的时候,考虑R中是否已经存在这个元素,如果已经存在,则不加入。如果不存在,则加入,并设置访问位为0。然后返回迭代判断。
最后当R中的元素不再增加的时候,为每一个元素设置一个新的节点,即对于每个元素a,都有一个f(a)与之对应。为f(a)设置邻接表,就是a的邻接表的拷贝,但是里面的目标地址b都变成了f(b)。这样我们就完成了nfa图的复制工作。由于有集合操作,主要任务为插入和查找,所以实现的时候考虑建立一个散列表,采取开放寻址的线性探查,来加速操作。
但是,如果我们证明了,任何一个假名的nfa节点的标号集合是一个连续的整数区间的话,我们就可以以非常高的效率来做到nfa图的复制。下面我们就来证明一个nfa图里面所有的标号刚好完全占据了一个整数区间,而这个证明需要数学归纳法。我们对一个正则表达式里面的假名嵌套深度来归纳。设s为嵌套深度。
当s为零的时候,即表达式里面没有引用。这个时候考虑我们在分配nfa节点时候的分配策略,我们保留了一个全局的nfa_node_number,每分配一个节点,这个就加1,然后把这个值当作节点的标号,这些节点都是一个一个连续分配的,而且他们没有进入的边,也没有出去的边。所以我们可以为这个正则表达式附加他的最小标号节点和最大标号节点,这样就可以避免集合操作,因为这之中的点都属于该正则表达式。而且这样在重新映射的时候,映射函数可以改为线性函数,直接采用加法规则就可以了。
现在考虑s为1的时候,即正则表达式中拥有一个s为0的假名的引用。由于nfa_node_number是全局的,我们考虑刚开始进入这个正则表达式的时候,可用的标号为a,当进入这个引用时,可用标号为b,即在拷贝nfa图的时候引起的节点分配是以b开始的。由于进行拷贝nfa图的时候,节点分配是连续的,假设拷贝完之后,可用标号为c,则b-c之间的标号都被使用了。由于a-b之间的标号都被使用了,所以a-c之间的标号也是都被使用了,因此a-c之间是连续的,并一直向右扩展,当这个正则表达式处理完的时候,可用标号为d,则a-d之间的标号都被这个正则表达式使用了,因此我们也可以设置这个正则表达式的开始标号与结束标号 。
虽然我们当前讨论的是不怎么严格的数学归纳,但是我们可以从上面的讨论可以看出,每一个假名所代表的正则表达式都有他的起始标号和结束标号,而且之间的标号都是被这个正则表达式所使用的,外部标号的节点不会跟这些标号的节点相连。因此我们可以将这两个域添加到这个假名的信息里面去。
我将用代码来描述如何维护这些信息,以及利用这些信息来做nfa图的复制。
正则转nfa:bug消除的更多相关文章
- 正则转nfa:bug出现。
本人写的一个正则到nfa的bug 刚写完前面的那篇,自己用脑子过了一下,发现了一个bug.具体情况如下. 这个bug的产生条件是多次调用假名的时候,每次调用都会修改假名的nfa图.直接这么说不好理解, ...
- 正则转nfa:完成
太累了,感觉不会再爱了.问题已经解决,具体的懒得说了. #include "regular_preprocess.h" //这个版本终于要上nfa了,好兴奋啊 //由于连个节点之间 ...
- 最初步的正则表达式引擎:nfa的转换规则。
[在此处输入文章标题] 正则到nfa 前言 在写代码的过程中,本来还想根据龙书上的说明来实现re到nfa的转换.可是写代码的时候发现,根据课本来会生成很多的无用过渡节点和空转换边,需要许多的代码.为了 ...
- Bug驱动开发(Bug-driven development)
说实话,作为一个Domino开发者,像測试驱动开发(Test-driven development).功能驱动开发(Feature-driven development)之类软件开发的高大上的方法论( ...
- 正则表达式引擎:nfa的转换规则。
正则表达式引擎:nfa的转换规则. 正则到nfa 前言 在写代码的过程中,本来还想根据龙书上的说明来实现re到nfa的转换.可是写代码的时候发现,根据课本来会生成很多的无用过渡节点和空转换边,需要许多 ...
- NFA/DFA算法
1.问题概述 随着计算机语言的结构越来越复杂,为了开发优秀的编译器,人们已经渐渐感到将词 法分析独立出来做研究的重要性.不过词法分析器的作用却不限于此.回想一下我们的老师刚刚开始向我们讲述程序设计的时 ...
- 使用方便 正则表达式grep,sed,awk(一)
一些无稽之谈: 对于正则表达式,永远似了解不明白,看到一些代码,脚本定期,awk,sed.心里总有点虚.主要是记不住.平时又没怎么用,也就没总结了. 如今有空,决定总结一下,顺便克服一下看到shell ...
- LinbDesk --- 新的extjs4.2 desktop demo : 技术交流Q群:336584192
很多朋友对extjs desktop感兴趣,就在原来简单的dsktop基础上,作了很多拓展 主要例如以下: 软件更新情况介绍: LinbDesk 拓展自Extjs 4.2的桌面Demo 拓展代码适用 ...
- 第一周Python学习笔记
Python 基本语法: ① Python程序的格式:1.用代码高亮来标识函数丶语句等等 本身的代码高亮并没有实际的意义,只是用来辅助编程人员和阅读人员 更好的识别 2.程序以缩进来标识语句,缩进用 ...
随机推荐
- 待整理 - Linux 下的VI命令大全
http://www.cnblogs.com/88999660/articles/1581524.html
- 开机自动播放音乐的vbs
今天无意间看到了vbs这小玩意,就突发奇想,自学了一下,倒弄出如下的小玩意,大牛勿喷!这个可用做撩妹神技也可以用于提醒自己!使用方法:复制程序到txt文本里面保存,然后改后缀为vbs,丢到C:\Pro ...
- input value的值不可改变
同样是东钿微信服务平台,使用积分的问题,原来的版本是,默认用户不使用积分,也就没有给input赋值,后面华总说默认让用户使用积分,于是我就信誓旦旦把从后台得到用户可使用的积分赋在input上,后来,用 ...
- CentOS6 下安装JDK7
1.下载JDK:http://www.oracle.com/technetwork/java/javase/archive-139210.html,选择Java SE 7,下载jdk-7u80-lin ...
- 更改VisualStudio默认创建类和接口不加public问题
由于VisualStudio创建类和接口时,默认的是不加public关键字的,而我们大多数时候创建的类都是public的,于是,为了更好工作觉得改之. 首先找到在VisualStudio安装目录下路径 ...
- Libvirt 网络管理
- Oracle-11g-R2 RAC 环境下 GPnP Profile 文件
GPnP Profile 文件的作用: GPnP Profile 文件是一个保存于 $GRID_HOME/gpnp/<hostname>/profiles/peer 目录下的小型 XML ...
- Java内存区域分析
程序计数器 指令运行的指示器. 每一个线程都有独立的程序计数器,互无影响,我们称这类区域为线程私有的内存. 运行Java方法,计数器记录的是正在运行的虚拟机字节码指令地址;假设运行的是native方法 ...
- iOS开发——UI篇Swift篇&UIWebView
UIWebView //返回按钮事件 @IBAction func backButtonClick() { self.navigationController?.popViewControllerAn ...
- range与xrange之间的差异(转)
range 函数说明:range([start,] stop[, step]),根据start与stop指定的范围以及step设定的步长,生成一个序列.range示例: >>> ra ...