正则到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消除的更多相关文章

  1. 正则转nfa:bug出现。

    本人写的一个正则到nfa的bug 刚写完前面的那篇,自己用脑子过了一下,发现了一个bug.具体情况如下. 这个bug的产生条件是多次调用假名的时候,每次调用都会修改假名的nfa图.直接这么说不好理解, ...

  2. 正则转nfa:完成

    太累了,感觉不会再爱了.问题已经解决,具体的懒得说了. #include "regular_preprocess.h" //这个版本终于要上nfa了,好兴奋啊 //由于连个节点之间 ...

  3. 最初步的正则表达式引擎:nfa的转换规则。

    [在此处输入文章标题] 正则到nfa 前言 在写代码的过程中,本来还想根据龙书上的说明来实现re到nfa的转换.可是写代码的时候发现,根据课本来会生成很多的无用过渡节点和空转换边,需要许多的代码.为了 ...

  4. Bug驱动开发(Bug-driven development)

    说实话,作为一个Domino开发者,像測试驱动开发(Test-driven development).功能驱动开发(Feature-driven development)之类软件开发的高大上的方法论( ...

  5. 正则表达式引擎:nfa的转换规则。

    正则表达式引擎:nfa的转换规则. 正则到nfa 前言 在写代码的过程中,本来还想根据龙书上的说明来实现re到nfa的转换.可是写代码的时候发现,根据课本来会生成很多的无用过渡节点和空转换边,需要许多 ...

  6. NFA/DFA算法

    1.问题概述 随着计算机语言的结构越来越复杂,为了开发优秀的编译器,人们已经渐渐感到将词 法分析独立出来做研究的重要性.不过词法分析器的作用却不限于此.回想一下我们的老师刚刚开始向我们讲述程序设计的时 ...

  7. 使用方便 正则表达式grep,sed,awk(一)

    一些无稽之谈: 对于正则表达式,永远似了解不明白,看到一些代码,脚本定期,awk,sed.心里总有点虚.主要是记不住.平时又没怎么用,也就没总结了. 如今有空,决定总结一下,顺便克服一下看到shell ...

  8. LinbDesk --- 新的extjs4.2 desktop demo : 技术交流Q群:336584192

    很多朋友对extjs desktop感兴趣,就在原来简单的dsktop基础上,作了很多拓展  主要例如以下: 软件更新情况介绍: LinbDesk 拓展自Extjs 4.2的桌面Demo 拓展代码适用 ...

  9. 第一周Python学习笔记

    Python 基本语法: ①  Python程序的格式:1.用代码高亮来标识函数丶语句等等 本身的代码高亮并没有实际的意义,只是用来辅助编程人员和阅读人员 更好的识别 2.程序以缩进来标识语句,缩进用 ...

随机推荐

  1. IIS7 “拒绝访问临时目录”

    创建 BlogConfigurationSettings 的配置节处理程序时出错: 拒绝访问临时目录.以其运行 XmlSerializer 的身份“IIS APPPOOL\5656qp.com.rmi ...

  2. 检查.net代码中占用高内存函数(翻译)

    哈哈,昨天没事做,在CodeProject瞎逛,偶然看到这篇文章,居然读得懂,于是就翻译了一下,当练习英语,同时增强对文章的理解,发现再次翻译对于文章的一些细节问题又有更好的理解.下面是翻译内容,虽然 ...

  3. 关于document.referrer的使用需要注意

    项目使用到一个场景,ajax请求返回无权限,跳回登录页面,登录后自动返回之前的浏览页,跳转由前端处理,于是想到document.referrer,但是对可靠性不确定,特意搜索了一下相关资料,大致整理如 ...

  4. Android实现静默安装与卸载

    一般情况下,Android系统安装apk会出现一个安装界面,用户可以点击确定或者取消来进行apk的安装. 但在实际的项目需求中,有一种需求,就是希望apk在后台安装(不出现安装界面的提示),这种安装方 ...

  5. c# 使用hook来监控鼠标键盘事件的示例代码

    如果这个程序在10几年前,QQ刚刚兴起的时候,有了这个代码,就可实现盗号了. 当然使用钩子我们更多的是实现"全局快捷键"的需求. 比如 程序最小化隐藏后要"某快捷键&qu ...

  6. maven的学习系列(四)—创建maven项目注意事项

    文件夹: <1> 中央工厂的位置 <2>mvn archetype:generate <3>Eclipse配置maven <4>在Eclipse中创建简 ...

  7. cdoj 25 点球大战(penalty) 模拟题

    点球大战(penalty) Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/2 ...

  8. Codeforces Round #310 (Div. 1) B. Case of Fugitive set

    B. Case of Fugitive Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/555/p ...

  9. 使用AmplifyJS和JQuery编写更好更优雅的javascript事件处理代码

    事件(或消息)是一种经常使用的软件设计模式.可以减少消息处理者和消息公布者的之间的耦合,比方J2EE里面的JMS规范.设计模式中的观察者模式(也叫公布/订阅模式).这对于javascript代码相同适 ...

  10. Swift 本地推送通知UILocalNotification

    Notification是智能手机应用开发中常用的信息传递机制,它不用消耗更多资源去不停的检查信息状态,可以非常好的节省资源. 在iOS中分为两种通知:本地.远程.本地的UILocalNotifica ...