说明:1.在学习过程中没看到此论坛中有好的python实现,所以写一篇文章作为补充。

2.不赘述正则表达式和NFA的概念,着重描述python的算法实现,以及过程中用到的数据结构(十分精妙)。

创建NFA的第一步是解析正则表达式,我看龙书中使用分析树来解析的,在这里卡了一段时间,后来查资料发现Thompson的原论文用的解析法是将正则式从前缀形式转换成后缀形式,对我来讲同样清晰易懂而且好实现,实现的复杂度时间复杂度是O(n)。举例来说,原正则表达式为a.b,a|b,(a|b).c,(a|b)*那么转换后分别为ab., ab|, ab|c和ab|*(符号“.”表示联合,“|”表示或,“*”表示任意)。这个转换算法叫 Shunting Yard 算法:

def shunt(infix):# Curly braces = dictionary# *, | are repetition operators. They take precedence over concatenation and alternation operators# * = Zero or more# . = Concatenation# | =  Alternationspecials = {'*': 50, '.': 40, '|': 30}pofix = ""stack = ""# Loop through the string one character at a timefor c in infix:if c == '(':stack = stack + celif c == ')':while stack[-1] != '(':pofix, stack = pofix + stack[-1], stack[:-1]# Remove '(' from stackstack = stack[:-1]elif c in specials:while stack and specials.get(c, 0) <= specials.get(stack[-1], 0):pofix, stack = pofix + stack[-1], stack[:-1]stack = stack + celse:pofix = pofix + cwhile stack:pofix, stack = pofix + stack[-1], stack[:-1]return pofix

第二步就是创建NFA。用什么数据结构表示NFA呢?其实很精炼,只用起始、接收两个状态表示即可。

class NFA:def __init__(self, start, end):self.start = startself.end = end# both start and end are States

State(状态)又怎么表示的呢?根据Thompson'NFA的要求,状态有两种转换方式-字符和空串(ε),字符只能转换到另外一个状态,空串最多转换到另外两个状态,两种转换不能同时进行。下面是状态的结构:

class State:def __init__(self, isEnd):self.isEnd = isEnd    # isEnd is boolself.transition = {}self.epsilonTransitions = []

给状态添加转换:

def addEpsilonTransition(come, to):come.epsilonTransitions.append(to)def addTransiton(come, to, symbol):come.transition[symbol] = to

创建两种基础NFA:

def fromEpsilon():start = State(False)end = State(True)addEpsilonTransition(start,end)return start, enddef fromSymbol(symbol):start = State(False)end = State(True)addTransiton(start, end, symbol)return start, end

这样所有的条件都具备了,创建符合正则表达式的NFA.

创建字符 "a" 的NFA,记作 N(a):

def createNFA(symbol):start, end = fromSymbol(symbol)return NFA(start, end)

创建字符"a|b"的NFA,联合N(a) 和 N(b) → N(a|b):

def union(first, second):start = State(False);addEpsilonTransition(start, first.start)addEpsilonTransition(start, second.start)end = State(True)addEpsilonTransition(first.end, end)first.end.isEnd = FalseaddEpsilonTransition(second.end, end)second.end.isEnd = False

创建闭集"(a|b)*"的NFA,N(a|b) → N((a|b)∗):

def closure(nfa):start = State(False)end = State(True)addEpsilonTransition(start, end)addEpsilonTransition(start, nfa.start)addEpsilonTransition(nfa.end, end)addEpsilonTransition(nfa.end, nfa.start)nfa.end.isEnd = Falsereturn NFA(start, end)

再补充一个联合的NFA,N(a.b):

def concat(first, second):addEpsilonTransition(first.end, second.start)first.end.isEnd = Falsereturn NFA(first.start, second.end)

现在我们把上述的算法放到一起,分析“(a|b)*.c”

先将这种前缀模式转换成后缀模式:

regex = '(a|b)*.c'
pofix = shunt(regex)
print(pofix)

返回

ab|*c.

创建一个栈(stack),并从左往右以此读取pofix.

1.若读取的是字符,创建字符NFA,压入栈中

2.若读取的是操作符,弹出栈中内容,创建操作符NFA,再压入栈

def toNFA(postfix):if postfix == '':return fromEpsilon()stack = []for c in postfix:if c == '.':nfa2 = stack.pop()nfa1 = stack.pop()new_nfa = concat(nfa1, nfa2)stack.append(new_nfa)elif c == '|':nfa2 = stack.pop()nfa1 = stack.pop()new_nfa = union(nfa1, nfa2)stack.append(new_nfa)elif c == '*':nfa = stack.pop()new_nfa = closure(nfa)stack.append(new_nfa)else:nfa = createNFA(c)stack.append(nfa)return stack.pop()          
postfix1 = 'ab|*c.'
nfa = toNFA(postfix1)

至此,算法结束。

根据正则表达式创建NFA的Thompson算法 python实现相关推荐

  1. NFA、DFA模拟、正则表达式转NFA、NFA转DFA、DFA转正则、DFA最小化的python实现项目

    各类自动机模拟实现 项目地址: https://github.com/HuiyuanYan/automaton_simulation 注:这个github链接必须复制重新在浏览器打开,不能通过CSDN ...

  2. 编译原理实验报告_任意给定一个正规式 r (包括连接、或、闭包运算),根据 Thompson算法设计一个程序,生成与该正规式等价的 NFA N 。

    任意给定一个正规式 r (包括连接.或.闭包运算),根据 Thompson算法设计一个程序,生成与该正规式等价的 NFA N . 百度网盘下载 传送门 提取码:bzjn

  3. 正则表达式转NFA,DFA,最小化DFA

    Exp 2:正则表达式转NFA,DFA,最小化DFA (1)正则表达式应该支持单个字符,运算符号有: 连接 选择(|) 闭包(*) 正闭包(+) 可选(?) 括号 (2)要提供一个源程序编辑界面,让用 ...

  4. c++自底向上算符优先分析_词法分析程序的自动生成器(二)——Thompson算法

    碎碎念:我写词法分析程序的自动生成器的时候,先写的NFA-DFA和DFA化简.之后发现因为正则表达式的结构太复杂了,比如描述Pl/0程序标识符的正则表达式是 (a|-|z|A|-|Z)( a|-|z| ...

  5. 《数据结构与算法 Python语言描述》 读书笔记

    已经发布博客 <数据结构与算法 Python语言描述> 读书笔记 第二章 抽象数据类型和Python类 2.1 抽象数据类型abstract data type:ADT 2.1.1 使用编 ...

  6. 一.正则表达式转换为有限状态自动机:正则表达式转NFA

    原文:https://study.163.com/course/courseMain.htm?courseId=1002830012 一.有限状态自动机的分类 有限状态自动机,其实可以分成两类.第一类 ...

  7. list 排序_十个必知的排序算法|Python实例系列

    十大排序: 1.冒泡排序2.选择排序3.插入排序4.希尔排序5.归并排序6.快速排序7.堆排序8.计数排序9.桶排序10.基数排序 完整代码和注释如下 # -*- coding: UTF-8 -*-# ...

  8. python正则表达式操作指南_第二篇详细Python正则表达式操作指南(re使用)

    接下来昨天的内容 执行匹配 一旦你有了已经编译了的正则表达式的对象,你要用它做什么呢?`RegexObject` 实例有一些方法和属性.这里只显示了最重要的几个,如果要看完整的列表请查阅 Python ...

  9. LeetCode 字符串简单部分 算法 python实现

    ''' #2018-06-02 June Saturday the 22 week, the 153 day SZ LeetCode 字符串简单部分 算法 python实现 https://leetc ...

  10. 数据结构python课后答案_数据结构与算法:Python语言描述 1~5章课后习题

    数据结构与算法:Python语言描述 1~5章课后习题 发布时间:2018-07-19 20:42, 浏览次数:1885 , 标签: Python MarkDown语法写的,不知道为啥上传到CSDN不 ...

最新文章

  1. 一生中需要的10种人脉
  2. 修改linux下全局数据库名,linux/unix下修改oracle数据库实例名的方法
  3. ajax前台传json到后台解析的方法以及注意事项
  4. jdbc获取mysql第二行表信息_【奇技淫巧】MySQL另类方法获取元数据信息
  5. nettry 入站事件如何传递到下一个handler
  6. VMware esxi 4.0如何更换序列号
  7. opencv中的merge函数
  8. 电子书下载:深入解析Windows操作系统第6版 Windows Internals 6th Part1, Part2
  9. qt 实现、区分鼠标单击,双击事件
  10. centerOS 7.6FTP安装与配置
  11. 双臂Matlab仿真建模:正运动学
  12. WinForGIFSicle 1.0.0.1 免费开源版,基于GIFSicle的开源可视化批量GIF压缩工具
  13. 微信小程序中如何有效的修改app.js中全局变量的值,并能在页面中进行动态响应
  14. MySQL 8.0完美卸载(windows)
  15. vue-manage-system : Vue2 后台管理系统解决方案
  16. 不安全!!!都2020年了,你的网站还没上HTPPS说得过去吗?
  17. SEM代码篇----R详细实现(SEM 2)
  18. V831——车牌识别
  19. 体验 正式发布 的OSM v1.0.0 版本
  20. 飞刀又见飞刀在线观看

热门文章

  1. cs系统如何上云服务器,cs架构程序怎么连接云服务器
  2. javax.crypto.BadPaddingException Given final block not properly padded?
  3. QT之如何添加现有文件
  4. 计算机为动态分区无法安装系统,磁盘动态分区形式的电脑怎么重装系统win10
  5. 举个栗子!Tableau 技巧(109):用 LOD 计算产品销售周期
  6. (完全解决)argparse中dest是什么意思
  7. 翟菜花:四家电商平台Q3财报梳理:涨幅狂欢后的沉思
  8. Qt+MPlayer音乐播放器开发笔记(一):ubuntu上编译MPlayer以及Demo演示
  9. spss modeler模型应用
  10. python的浅拷贝和深copy