根据正则表达式创建NFA的Thompson算法 python实现
说明: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实现相关推荐
- NFA、DFA模拟、正则表达式转NFA、NFA转DFA、DFA转正则、DFA最小化的python实现项目
各类自动机模拟实现 项目地址: https://github.com/HuiyuanYan/automaton_simulation 注:这个github链接必须复制重新在浏览器打开,不能通过CSDN ...
- 编译原理实验报告_任意给定一个正规式 r (包括连接、或、闭包运算),根据 Thompson算法设计一个程序,生成与该正规式等价的 NFA N 。
任意给定一个正规式 r (包括连接.或.闭包运算),根据 Thompson算法设计一个程序,生成与该正规式等价的 NFA N . 百度网盘下载 传送门 提取码:bzjn
- 正则表达式转NFA,DFA,最小化DFA
Exp 2:正则表达式转NFA,DFA,最小化DFA (1)正则表达式应该支持单个字符,运算符号有: 连接 选择(|) 闭包(*) 正闭包(+) 可选(?) 括号 (2)要提供一个源程序编辑界面,让用 ...
- c++自底向上算符优先分析_词法分析程序的自动生成器(二)——Thompson算法
碎碎念:我写词法分析程序的自动生成器的时候,先写的NFA-DFA和DFA化简.之后发现因为正则表达式的结构太复杂了,比如描述Pl/0程序标识符的正则表达式是 (a|-|z|A|-|Z)( a|-|z| ...
- 《数据结构与算法 Python语言描述》 读书笔记
已经发布博客 <数据结构与算法 Python语言描述> 读书笔记 第二章 抽象数据类型和Python类 2.1 抽象数据类型abstract data type:ADT 2.1.1 使用编 ...
- 一.正则表达式转换为有限状态自动机:正则表达式转NFA
原文:https://study.163.com/course/courseMain.htm?courseId=1002830012 一.有限状态自动机的分类 有限状态自动机,其实可以分成两类.第一类 ...
- list 排序_十个必知的排序算法|Python实例系列
十大排序: 1.冒泡排序2.选择排序3.插入排序4.希尔排序5.归并排序6.快速排序7.堆排序8.计数排序9.桶排序10.基数排序 完整代码和注释如下 # -*- coding: UTF-8 -*-# ...
- python正则表达式操作指南_第二篇详细Python正则表达式操作指南(re使用)
接下来昨天的内容 执行匹配 一旦你有了已经编译了的正则表达式的对象,你要用它做什么呢?`RegexObject` 实例有一些方法和属性.这里只显示了最重要的几个,如果要看完整的列表请查阅 Python ...
- LeetCode 字符串简单部分 算法 python实现
''' #2018-06-02 June Saturday the 22 week, the 153 day SZ LeetCode 字符串简单部分 算法 python实现 https://leetc ...
- 数据结构python课后答案_数据结构与算法:Python语言描述 1~5章课后习题
数据结构与算法:Python语言描述 1~5章课后习题 发布时间:2018-07-19 20:42, 浏览次数:1885 , 标签: Python MarkDown语法写的,不知道为啥上传到CSDN不 ...
最新文章
- 一生中需要的10种人脉
- 修改linux下全局数据库名,linux/unix下修改oracle数据库实例名的方法
- ajax前台传json到后台解析的方法以及注意事项
- jdbc获取mysql第二行表信息_【奇技淫巧】MySQL另类方法获取元数据信息
- nettry 入站事件如何传递到下一个handler
- VMware esxi 4.0如何更换序列号
- opencv中的merge函数
- 电子书下载:深入解析Windows操作系统第6版 Windows Internals 6th Part1, Part2
- qt 实现、区分鼠标单击,双击事件
- centerOS 7.6FTP安装与配置
- 双臂Matlab仿真建模:正运动学
- WinForGIFSicle 1.0.0.1 免费开源版,基于GIFSicle的开源可视化批量GIF压缩工具
- 微信小程序中如何有效的修改app.js中全局变量的值,并能在页面中进行动态响应
- MySQL 8.0完美卸载(windows)
- vue-manage-system : Vue2 后台管理系统解决方案
- 不安全!!!都2020年了,你的网站还没上HTPPS说得过去吗?
- SEM代码篇----R详细实现(SEM 2)
- V831——车牌识别
- 体验 正式发布 的OSM v1.0.0 版本
- 飞刀又见飞刀在线观看
热门文章
- cs系统如何上云服务器,cs架构程序怎么连接云服务器
- javax.crypto.BadPaddingException Given final block not properly padded?
- QT之如何添加现有文件
- 计算机为动态分区无法安装系统,磁盘动态分区形式的电脑怎么重装系统win10
- 举个栗子!Tableau 技巧(109):用 LOD 计算产品销售周期
- (完全解决)argparse中dest是什么意思
- 翟菜花:四家电商平台Q3财报梳理:涨幅狂欢后的沉思
- Qt+MPlayer音乐播放器开发笔记(一):ubuntu上编译MPlayer以及Demo演示
- spss modeler模型应用
- python的浅拷贝和深copy