本文参考了:java
这是《计算理论101》系列的第一篇,将从最基本的有限状态机讲起。主要参考的课程和书籍有: Introduction to the Theory of Computation 3rd Edition 和 【Stonehill college CS】Introduction to the Theory of Computation 。git
如 Stonehill college 的 Professor of Computer Science Shai Simonson所说,这多是计算机课程中最抽象的一门了,但倒是任何 computer scientist(我以为能够延生至任何真正热爱 CS 的人)至少须要了解的一门课。这门课不会教你如何写代码,也不会教你如何作一个计算机,而是着重于『计算机科学』中的『科学』两个字,去了解计算机科学发展几十年来前人闪耀的思想。程序员
还有一点,我认为也是很重要的,那就是学习新知识那份最单纯的快乐。github
好了,废话很少说,开始正题~正则表达式
以一个程序员的角度,个人理解就是内存有限的一个机器,上面定义了一些函数,能够从一个状态跳转到另外一个状态。严格的数学定义,一个有限状态机能够定义为一个五元组,以下图表示(来源于Introduction to the Theory of Computation 3rd Edition P35):算法
能够用图直观地表示:下图这个状态机,圆圈表示的是可能出现的状态,可能输入的值为0和1,装换函数就是那些箭头,开始状态为 q1,accept 状态为 q2(用双圆圈表示)。编程
一个有限状态机的定义其实就是这么简单。微信
有限状态机一个最显然的特色就是内存有限,没法记忆全部的历史输入,因此它可以解决的问题是有限的。至于什么问题可以解决,什么不能,后面再说。先来看看有限状态机的应用。函数
这是《Introduction to the Theory of Computation 3rd Edition》书中提到的一个例子。gitlab
下图中,门口和门背各有一个感应器(front 为门口,rear 为门背)。门的控制开关一共有两个状态:OPEN 和 CLOSED,输入一共有四种状况:FRONT(门口有人)、REAR(门背有人)、BOTH(门口门背都有人)、NEITHER(两边都没人)。
有一个图表示状态转换过程为:
稍微解释一下:
我对于这个门的设计表示怀疑,处于 CLOSED 状态时,难道 REAR PAD 检测到人不该该变成 OPEN 状态吗?也许是我哪里理解得不对,有童鞋知道的欢迎指出。不过这一点不影响咱们对于有限自动机的理解。
这个自动门其实就能够看做是一个最简单的计算机了,它只有一个 bit 的存储空间,能够记录当前门的状态是OPEN 仍是 CLOSED。相似的还有电梯, 饮料机 等等。
事实上,最开始咱们骨灰级的程序员(计算机科学家)们,面对的就是相似的状况,存储空间极其有限。如今的不少嵌入式设备,内存一样很是有限,因此有限状态机仍是有用武之地的。
这里推荐一个网站: regexper.com/ ,可以很是直观地将正则表达式还原为一个 finite state machine。另外开源地址以下: gitlab.com/javallone/r… 。
举几个正则表达式例子:
匹配手机号:/^1(3|4|5|7|8)\d{9}$/
:
匹配邮箱:^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$
匹配 IP 地址:^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
这里不深刻代码层,否则这篇文章就讲不完了。有兴趣的童鞋本身 Google 一下,后面有机会可能会再次讲到。
这个 stackexchange 的连接里面提到了不少: softwareengineering.stackexchange.com/questions/4…
设计一个FSM,可以识别被3整除的二进制字符串。好比accept 1001
,reject 1101
。 首先,咱们能够把全部余数(reminder)的可能性看成状态,也就是三个状态:0,1,2,其中0时 accept 状态。 而后分析一下状态转换是怎么样的?二进制数,末位添加一个0表示乘以2,末位加1表示乘以2再加1,对于余数,一样是乘2或者乘2加1,只不过余数会『进位』。
这样就作完了,一个用普通算法很难解决的问题,用FSM是否是很简单?会设计识别能被3整除的 FSM,接下来被四、五、六、七、8整除的是否是也会了?这里,被2^k(k=1,2,3,4)整除还有一个更简单的方法:转换为判断末位至少有k 个0。
动手来画一画:
设计一个 FSM,可以识别 能被4整除的二进制字符串(末尾至少有两个0)。 这里把状态设计为目前为止末尾收到了几个0,一共有三个状态:0个0,1个0,2个0。
有这个还能够推广到模式字符串识别,好比要识别特定子字符串 ,请看下面这个例子。
设计一个 FSM,可以识别子字符串abcab
。
为了简单起见,这里把圆圈省略掉了,同时把中间的某些节点的状态转换忽略掉了。
状态机的定义很是简洁,可是功能很强大,并且很是有意思不是吗?
码字很辛苦,图文并茂更辛苦,点个赞鼓励一下~
广告时间,欢迎你们关注个人微信公众号。同时本文同步于 github: github.com/liaochangji…