nfa状态转换图正规式_用有限状态自动机判断十进制数

验证十进制数字
本文介绍了一种利用自动机理论来判断字符串是否为有效十进制数字的方法。通过构造正则表达式、NFA及DFA,最终形成状态转换表,并提供Python实现。

题目描述

验证给定的字符串是否可以解释为十进制数字.

示例:

"0" => true" 0.1 " => true"abc" => false"1 a" => false"2e10" => true" -90e3   " => true" 1e" => false"e3" => false" 6e-1" => true" 99e2.5 " => false"53.5e93" => true" --6 " => false"-+3" => false"95a54e53" => false数字: 0-9小数点: .符号: +, -指数: e

解题思路

看过题解的同学应该发现了, 如果用Python, 很多人直接调用float函数, 如果转换成功则返回True, 如果抛出异常, 则返回False. 不得不说, 还真是个小机灵鬼呢~. 但是这种方式求解, 对于提升自己没什么太大的帮助. 下面讲一下如何用自动机理论去求解这道题, 已经忘了自动机为何物的同学先翻一下编译原理教材, 或者参考维基百科.

我们的目标是构造出一个DFA, 模拟输入字符串在DFA上的运行, 如果处理完输入的最后一个字符, DFA处在接受状态, 那么该字符串可以解释为十进制数, 否则不能. 但是很难直接构造出一个满足条件的DFA, 需要经过一个曲线救国的过程, 首先, 构造出一个能匹配目标字符串的正则表达式, 根据正则表达式构造出对应的NFA, 最后将NFA转换成等价的DFA, 有了这个DFA之后就可以构造出其对应的状态转换表, 并且在代码中使用了.

如何构造能够匹配十进制数的正则呢? 先说先我的思路, 一个十进制数可以划分成3个部分, 即: 1) 符号位; 2) base; 3) 幂次; 比如"-123.32e+4", 其中符号位和幂次可以为空, 并且这两部分的正则比较容易写. base部分有"23.", "23.34", "23", ".34"四种形式, 写一个匹配这4种形式的正则也比较容易, 各位看官可以自己实现一下, 各部分的正则写完之后拼接起来即可.

有了正则之后可以构造对应的NFA了, but how? 先看下正则表达式, 主要包含连接, 或, 闭包三种基本操作, 再复杂的正则也是由这三种基本操作组合而成的, 只需要了解这三种基本操作的NFA如何构造, 就可以构造出上面得到的正则对应的NFA了, 具体实现参考Thompson算法.

有了NFA之后, 需要构造等价的DFA, 所谓等价是二者接受的字符串集合相同, 因为NFA的状态转移不确定, 转成DFA之后方便模拟运行. 通常使用子集构造算法进行NFA到DFA的转换, 为了得到DFA的状态转换表, 这里根据之前计算出的NFA手动模拟了子集构造算法的运行, 得到的状态转换表如下:

d153410cb0b4248afc18c0da317676fa.png

DFA状态转换表

其中状态2, 4, 5, 7, 8, 10是接受状态

代码实现

class Solution:    table = [        [1, 2, 3, -1, -1],        [-1, 2, 3, -1, -1],        [-1, 4, 5, 6, -1],        [-1, 7, -1, -1, -1],        [-1, 4, 8, 6, -1],        [-1, 7, -1, 6, -1],        [9, 10, -1, -1, -1],        [-1, 7, -1, 6, -1],        [-1, 8, -1, 6, -1],        [-1, 10, -1, -1, -1],        [-1, 10, -1, -1, -1]    ]    finals = [0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1]    def isNumber(self, s: str) -> bool:        return Solution.dfa(s)    @staticmethod    def dfa(s: str) -> bool:        s = s.strip()        q = 0  # DFA的初始状态        for ch in s:            q = Solution.move(q, ch)            # 跟踪状态转换            # print("state: %d" % (q))            if q == -1:                return False        return Solution.finals[q] == 1    @staticmethod    def move(q: int, ch):        if ch in '+-':            idx = 0        elif ch in '0123456789':            idx = 1        elif ch in '.':            idx = 2        elif ch in 'e':            idx = 3        else:            idx = 4        return Solution.table[q][idx]

更多leetcode题解敬请期待。

实验1词法分析器的实现 1.实验目的 掌握简单词法识别程序的分析、设计与实现的基本技术与一般方法。 2.实验题目 假设某语言允许的标识符为字母开头的字母数字串,允许的数据为无符号的十进制或十六进制整数。其中规定十六进制数必须以数字打头、以H结尾,数中允许使用的字母为A,B,C,D,E,F(分别表示10~15)。试设计一个DFA,使它能识别标识符、无符号的十进制和十六进制整数(假定各单词之间用界限符或空格分开),并编制相应的词法识别程序。 输入:可以自定义符号串的输入形,如键盘输入、文本文件、字符数组等。 输出:标识出规范的符号串与不合规范的符号串。 例: 若输入:" Ae35 6638 5392H A10 83A2Eh 65Ha 3G2H 80 " 则输出:Ae35是一个标识符(Identifier) 6638是一个十进制整数(Decimal Integer) 5392H是一个十六进制数(Hex Digit) A10是一个标识符(Identifier) 83A2Eh是一个十六进制数(Hex Digit) 65Ha非法输入(Invalid Input) 3G2H非法输入(Invalid Input) 80是一个十进制整数(Decimal Integer) 3.实验要求 (1)编写完整的实验报告,报告中要体现出分析设计实现等几个过程; (2)有完整的源代码,源码有规范的注释,无明显的语法错误; (3)实验报告按照《海南大学学生实验报告》的格要求书写; (4)严禁相互抄袭,否则实验成绩以0分记。 4.实验步骤 (1)分析与设计 a)根据给定的语言求出其正规(或文法) b)构造相应的NFA c)将NFA转换成DFA,并将其最小化 (或者直接给出最小化的DFA) (2)编程 a)根据最小化的DFA绘制程序流程(主要的) b)编写词法分析程序 (3)系统调试 请写出实验过程及结果
04-01
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值