词法分析:从RE(正则表达式)到DFA(确定的有限状态机)

正则表达式和自动机(DFA&NFA) 文章目录一 正则表达式匹配原理1.1 正则表达式1.2 DFA1.3 正则表达式和DFA的关系1.4 正则匹配过程二 DFA的构建三 DFA与正则的转化3.1 DFA转正则表达式3.2 正则表达式转DFA3.2.1 正则表达式转NFA3.2.2 NFA确定化四 js中的正则 一 正则表达式匹配原理 1.1 正则表达式 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。例如,筛选所有以包含连续 阅读详情

模式识别(Pattern recognization)是现在非常流行的一个词,我们对词法的分析也是基于模式(pattern-based)的。我们用正则表达式(Regular Expression)来定义单词的模式,而在词法分析时,有限状态机(Finite Automata)更便于我们分析。本文介绍将正则表达式(RE)转为确定的有限状态机(DFA)的方法。
首先,什么是确定的有限状态机,什么是非确定的有限状态机(NFA)?用通俗的语言讲,在面对相同的输入参数时,NFA可能会跳转到多种状态,而DFA只会跳转到特定的状态,有DFA类似于函数,而NFA类似一对多的映射。
DFA用程序可以描述为:

state = 1;
while (true) {
    ch = getChar();
    switch(state) {
    case 1:
        if (ch == 'a')
            state = 1;
        else if (ch == 'b')
            state = 2;
        else error();
        break;
    case 2://终止状态
        if (ch == 'a') state = 2;
        if (ch == '1') state  =2;
        else {
            ungetChar();//把取出的字符放回去
            return ID;
        }
    }
}

从上面的代码段,我们需要知道:

  • DFA=>program:从确定的有限状态机可以生成确定的程序
  • Each state=>a fragment of code:每个状态对应一个case。
  • Each edge=>a judgement:每条边对应一个if判断

从RE推出DFA的步骤:RE=>NFA=>DFA=optimization=>DFAo=>program

1. 从RE到NFA

从正则表达式到非确定的有限状态机对于人来说非常好理解,但是对于机器来说确比较复杂。从RE到DFA有两种方法:自顶向下逐步分解法和自下而上组合方法(Thompson方法)。

自顶向下逐步分解法:Top-down stepwise refinement according to the structure of RE

这种方法符合人的思维习惯,首先我们从最简单的情况开始考虑。
base
以(a|b)* a (a|b) (a|b)为例,这个正则表达式符合上面的αβ特征,因此第一步可以变成:
base1
而对于(a|b)*,又符合上面的a*特征,因此(a|b)*可以继续分解为
base2
可以看到a|b还可以继续分解,类似这样的分解过程到所有边的标记只剩下ε或字母表的单一字符为止。
然而,对于计算机来说,字符是一个一个读入的,计算机不能从整体把握情况逐步向下分解,因此我们还需要适合计算机的方法。

自下而上组合法:Bottom-up combination(Thomson方法)

这种比前一种方法稍微复杂一点,但其实想法也很简单,我试着换一种表述来解释这个方法。
在遇到单个的字符时,我们直接构造转换图,比如遇到a时,我们就构造这样的转换图:
a
这样,我们就形成了一个单元U,这个U就是上面已经生成的转换图。
在遇到操作符时,我们所有的处理都是针对单元的,在下面的图示中,我们用虚线圆圈表示一个单元。
op
在处理完操作符后形成的仍是一个单元,处理完后的整体变成单元U’参与下一次处理。这里类似于一种递归的过程。
但是,像a|b这样的式子,在处理‘|’这个操作符时,我们显然需要两个单元,但计算机在读到‘|’操作符时,我们在为a构造了转换图,计算机还不知道b的存在,也就不能做上面这样的处理,所以这种方法需要以下条件:

  • 正则表达式(RE)需要处理为后缀表达式
  • 正则表达式(RE)中需要写明操作符‘.’,如ab需要写为a.b

满足以上条件后,计算机可以用这种方法自动生成NFA。

2. 从NFA到DFA

对于一个已经形成的NFA,我们需要定义新的状态来形成DFA。首先要解释两种方法和他们对应的使用情形。
NFA之所以为NFA而不是DFA,主要是因为以下两个原因,解决以下的两种情形,就能将NFA转为DFA。

边上的ε:ε闭包

dfa
遇到这种情况,后面的三个状态完全可以合并,如果将后面的三个状态合为一个,那这个转换图里就没有ε边,也就满足了DFA的条件。
对应的解决方法是找出ε闭包,也就是先找出该状态的ε边推出的所有状态,再找那些状态的ε边推出的状态,是一个迭代的过程,直到找出一个状态的ε闭包。如果是从状态x开始的,我们将通过该过程找到的所有状态集称为以x状态为核的ε闭包,记为ε-closure({x}),或ε-c({x})。从定义可以知道,核相同,推出的ε闭包一定相同。

不确定的后续状态:子集构造法

dfa
遇到这种情况,如果能将状态2和状态3合并到一起,就不会出现“面对相同的输入状态可能跳转到多种状态的情形了”,合并状态2和状态3这样类似的状态的方法叫做子集构造法,若从状态Ii开始,以a边推出的所有状态集合为B,我们记为Ii–a–>B,比如上图可以记为1-a->{2,3}

综合使用:表驱动法

上面只是简单介绍了两种情形,说明了从NFA转化到DFA的重点是重新组合NFA状态。下面我们讨论系统的可编程的过程来将NFA转化为DFA,运用的还是上面的两种方法,我们需要构建一张表来展示构建的DFA里的所有状态。
以下图中的NFA为例:
nfa example

DFA State Ii (这里是新生成的DFA里的状态)a(这个状态从a边推出什么状态)b (这个状态从b边推出什么状态)
I0=ε-c({x})={x,5,1}ε-c(I0-a->{5,3})={5,3,1}=I1ε-c(I1-b->{5,4})={5,4,1}=I2
I1={5,3,1}……
I2={5,4,1}……

解释:首先从起点x开始构造新的DFA里的第一个状态I0,也就是寻找以x为核的ε闭包ε-c({x}),然后构造新的I0从a、b边推出的状态,方法是先使用子集构造法,再寻找构造后的子集的ε闭包。这样我们就找到了新的状态I1,I2,第二行、第三行就是寻找I1,I2以a、b边推出的状态,这样就能找到更多的状态,当没有新的状态产生时,这样的过程终止。这类似于一种迭代的过程。
这题最终的结果是:
resut

3. 从DFA到DFAo(DFA优化)

在上面生成的DFA中,每个状态都有以a、b推出的状态,有时候这可能意味着多余。DFA优化(Optimization of a DFA)的思想是减少DFA中的状态,我们用到离散数学中等价类划分的思想,如果两个状态等价,那么他们属于同一个等价类,我们只需要选择其中的一个代表即可。
如何划分等价类呢?

1)找出终止状态

什么样的状态可以被称为终止状态呢?在上例的NFA图中,y状态为终止状态。我们要做的是在I0~I6中找出终止状态。我们这样定义新的DFA中的终止状态:若Ii∩y ≠∅,则Ii为DFA中的终止状态。
因此第一步我们将上面的状态分为两类:终止状态和非终止状态。
optimization

2)划分等价类

第一步已经将状态分为了两类,下面我们要继续拆分。我们规定这样的这样的状态Ii,Ij属于同一个等价类:

  • Ii,Ij发出的边数相同。
  • Ii,Ij发出的边相同。
  • 对应相同的边连接的状态属于同一个等价类。

如I0和I1,他们对应的a边发出的状态分别是I1和I3,而在第一步中这两个状态已经被划分到了两类里,一定不是等价的,所以我们将I0,I1拆分,也就是将I0单独分出去。
op

3)回头看

在划分完后面的等价类时,我们还要回头看一下前面的等价类还可不可以划分。有时候前面在比较时后面的类还没有划分,因此判断属于同一个等价类不拆分,而到后面等价类判断时拆分了这个等价类,前面判断的两个状态可以就到了不同的等价类里,这就需要我们回头检查是不是所有的类都不能再拆分了。

4)选取代表

分好等价类后每个类选取一个状态作为代表,这个类的其他状态都用这个代表代替,重新构造DFA转化图。

这样,我们就将RE转换成优化后的DFA,尽管过程比较复杂,但是这样机械而固定的过程是可以编程解决的。在构造完DFA后,我们可以开始做更多的词法分析工作。

C++实现正则表达式转最小化DFA过程详解 目前学校正在开编译原理这门课。为了加深对正则表达式转最小化DFA的理解,利用c++编写了这个程序。现在把我的程序及实现的方法分享出来,希望能对大家的学习有所帮助。 本文主要从以下几个方面进行讲解正则表达式操作数运算符算法流程1.正则表达式的预处理2.中缀表达式转后缀表达式3.后缀表达式创建NFA4.NFA转化为DFA5.DFA的最小化合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片... 阅读详情

相关推荐

南开编译原理期末核心:词法分析与LL(1)语法分析实战精要

词法分析器与LL(1)语法分析是编译原理课程的两大基石,其本质是将正则表达式和上下文无关文法转化为可执行的状态机与预测分析表。理解DFA构造过程与FIRST/FOLLOW集计算逻辑,不仅关乎理论正确性,更直接影响语法分析器的可调试性与工程落地能力。在教学实践中,手写状态迁移、显式填表、冲突标注等规范操作,已成为高校期末考核与考研复试的关键能力指标。本文聚焦南开大学编译原理真题场景,以词法分析器实现和LL(1)预测分析表构建为双主线,系统拆解从正则表达式到token序列、从文法定义到推导步骤的完整技术链路,助

weixin_33766805的博客 346

正则表达式转NFA(C++代码)

#include <iostream> #include <vector> #include <string> #include <map> #include <stack> #include <fstream> using namespace std; class NFA { string name; // NFA name string re; // 正则表达式 string re_

qq_44951010的博客 6235

正则式转成最小DFA C++编写 设计含文档

正则式转成最小DFA C++编写 设计含文档 正则式转成最小DFA C++编写 设计含文档

正则到DFA

将正则表达式翻译成DFA的最简单算法是通过中间构造,在它之中,正则表达式派生出一个NFA,接着就用该NFA构造一个同等的DFA。。因此我们只关心两个算法:一个是将正则表达式翻译成N FA,另一个是将N FA翻译成D FA。构造一个扫描程序的自动过程可分为3步,如下所示:    (1)利用Thompson结构将正则表达式转换成NFA 基本正则表达式 基本正则表达式格式a、 或,其

Gikieng的奋斗路 2349

ros_control硬件接口实战:从零构建机器人控制框架

本文详细介绍了ros_control硬件接口在机器人控制框架中的核心作用与实践方法。通过解析硬件接口类型、实现标准接口、构建主控制循环及自定义功能扩展,帮助开发者从零构建高效的机器人控制系统,提升硬件与ROS的协同效率。

lstm7chronicler的博客 500

Office如何通过VSTO进行WORD插件开发?

VSTO(Visual Studio Tools for Office )是VBA的替代,是一套用于创建自定义Office应用程序的Visual Studio工具包。VSTO可以用Visual Basic 或者Visual C#扩展Office应用程序(例如Word、Excel、PPT)。本文通过VSTO进行Word插件开发总结,并进行记录。

【cacrle】的博客 7319

正则表达式(RE)、有限自动机(FA)和词法分析(LA)

关键词:正则表达式、RE、有限自动机、DFA、NFA、词法分析器、Thompson算法、子集构造算法、Hopcroft算法

Dong_HFUT的博客 7646

树莓派4B:控制步进电机

文章目录准备阶段接线阶段树莓派程序 准备阶段 准备以下物品,淘宝都可以买到: 57步进电机 电源开关(220v转24v,3A,72W) 步进电机驱动器 电源线 电线 杜邦线 树莓派4B一套 具体型号如下: 接线阶段 整体:接线效果如下图 电源开关起220v转24v作用,很好接线,输出24v接入步进电机驱动器 步进电机驱动器的 A+ A- B+ B- 按提示接步进电机四线,步进电机上就会有说...

学习路上的鸭子的博客 1万+

编译原理:词法分析(正则表达式->NFA->DFA->最小化DFA)

本文是作者对之前编译原理课程项目中词法分析模块的正则表达式->NFA->DFA->最小化DFA功能的总结归纳和思路整理展示,并结合一个具体用例帮助读者更好地了解其中转化思路和算法设计。

weixin_50833596的博客 2217

第二十一篇: `man`, `tldr`, `explain` - 授人以渔的“终极指令”

我们已经一起学习了19个(组)关键命令,从nvidia-smi到kubectl。但这只是GPU运维武器库中的一小部分。技术日新月异,新的工具、新的参数会不断涌现。这个系列的真正目的,不仅是教会你使用这19件“兵器”,更是希望你掌握学习任何一件新兵器的方法论。这套方法论就是你的“终极指令”。授人以鱼不如授人以渔。至此,《GPU运维指令集:20个关键命令的战地手册》系列已全部完结。我们从nvidia-smi出发,一路探索了监控、诊断、容器、集群、网络、性能等各个维度的命令,最后用自动化脚本将它们串联,又用。

weixin_42587823的博客 1350

ETL基础概念及要求详解

ETL即Extract(抽取)Transform(转换)Load(装载)的过程,如下图,同时也包括数据清洗的部分,是数据从源端到目标端的一个数据处理的过程,是构建数据仓库的重要一环,但不局限于构建数据仓库其他BI(商业智能)的设计和开发数据分析平台也经常用到ETL。

qq_43605229的博客 8943

编译原理之正则表达式RE和词法分析NFA(第一篇)

编译器,词法分析器,NFA,DFA

Lue的博客 1584

12、激光制造中人工智能与机器学习的应用及挑战

本文探讨了人工智能与机器学习在激光制造中的应用,重点分析了图像分类技术在质量检测中的多种方法及其性能对比,包括基于贝叶斯分类、卷积神经网络(CNN)和多尺度CNN的技术。同时,文章指出了AI在激光制造中面临的五大挑战:鲁棒性、安全性、可解释性、责任归属和可预测性,并提出了相应的解决思路。此外,还介绍了激光制造的主要应用技术如切割、焊接和增材制造的流程、优势与局限性,并通过对比表格直观展示不同技术的特点。最后展望了未来激光制造向智能化、自动化和可持续化发展的趋势。

rgv234567的博客 138

【编译原理】编译原理知识点汇总·词法分析器(正则式到NFA、NFA到DFA、DFA最小化)

通过上面的学习,我们已经对文法和词法有了更深入的理解。 词法就是字母如何组成单词———采用正则表达式就可以定义组成规则。 文法就是单词如何组成句子———采用产生式+推导就可以定义文法。 词法分析器的任务 判断单词是否符合正则表达式的规则。 明确给出合法单词的属性Token(保留字、标识符、运算符、界符、常量等)。

十二月的猫 2698

低代码组件开发——OpenClaw智能助手的组件设计与开发(2026技术版)

OpenClaw智能助手的低代码组件开发平台采用分层架构设计,包含组件定义、注册、配置、渲染和生命周期管理等核心模块。该系统支持UI、功能、数据和集成四种组件类型,强调可重用性、可配置性和可扩展性。组件定义通过TypeScript、React等技术实现组件结构和行为的描述,组件注册中心基于Node.js和MongoDB管理组件版本。该平台通过React、Redux等技术实现组件渲染和状态管理,并提供完整的生命周期管理机制。这种架构设计显著提升了智能助手应用的开发效率和质量。

一键难忘的博客 407

IgH EtherCAT 从入门到精通:第 2 章 环境搭建与编译安装

环境搭建与编译安装指南 本章详细介绍了搭建IgH EtherCAT Master开发环境的完整流程。内容包括: 硬件要求:支持多种Intel和Realtek网卡的原生驱动,以及通用网卡的generic驱动选项 软件依赖:列出Linux系统下所需的工具链和开发包 源码获取:通过Git克隆官方仓库并切换稳定版本的方法 配置选项:详细解析bootstrap脚本和configure的核心参数,包括路径设置、功能开关和实时框架选项 编译流程:从生成构建系统到最终编译安装的完整步骤 通过本章指导,读者可以完成一个可运行

从事嵌入式linux android驱动开发,拥有全栈能力 478

INT201 决策,计算,语言 笔记

xjtlu INT201 课程的个人总结笔记

sanmusen_wu的博客 5708

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

C++ 正则表达式

正则表达式 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。 正则引擎主要可以分为两大类:一种是DFA,一种是NFA。主流的正则引擎又分为3类:1. DFA引擎 DFA 引擎在线性时状态下执行,因为它们不要求回溯(并因此它们永远不测试相同的字符两次)。DFA 引擎还可以确保匹配

singebogo的博客 880

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Engineering a Compiler读书笔记(2):词法分析器

词法分析器 简介: || 词法分析流程: 读取字符流,,并应用一组规则来判断每个单词在源语言中是否合法,如果单词判断为有效,则会给它分配一个词类,将其聚合形成单词流。 || 手工编写的词法分析器因为避免了很多不必要的开销,故比生成的词法分析器,带来极大的性能优势的好处,往往超出了自动生成语法分析器的便利性带来的好处 || 程序设计语言的词法结构(微语法):规定了如何将字符组合为单词 (注意:语法是...

fang 0 jun的博客 774

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

编译器的编译基本过程

编译器最基本的功能就是把高级语言(例如C/Fortran)编写的代码转化为机器指令(就是01串),从这个角度来说它本质上是个转换过程。经典的编译过程主要包括: 1、词法分析(Lexical Analysis) 词法分析就是从输入代码中识别出各种记号(token),例如对于C语言我们就需要知道if,else等是语言的关键字,myvar是个标识,而123myvar不能被识别为一个标识。负责实现

u012388497的专栏 643

编译器基本过程

编译器最基本的功能就是把高级语言(例如C/Fortran)编写的代码转化为机器指令(就是01串),从这个角度来说它本质上是个转换过程。经典的编译过程主要包括: 1、       词法分析(Lexical Analysis) 词法分析就是从输入代码中识别出各种记号(token),例如对于C语言我们就需要知道if,else等是语言的关键字,myvar是个标识,而123myvar不能被识别为一个标识

Heron——Linux & ARM 1907

【编译原理】编译器的编译基本过程

编译器的编译基本过程 原文出处: 崤嶙的博客 编译器最基本的功能就是把高级语言(例如C/Fortran)编写的代码转化为机器指令(就是01串),从这个角度来说它本质上是个转换过程。经典的编译过程主要包括: 1、词法分析(Lexical Analysis) 词法分析就是从输入代码中识别出各种记号(token),例如对于C语言我们就需要知道if,else等是语言的关键字,myvar

CPP工程师的专栏 3366
上一篇: 补充:消除epsilon产生式等
下一篇: 从上下文无关文法(CFG)到语法分析树——LL(1)分析法
cuiods
博客等级 码龄12年 41粉丝 15原创
评论 17
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值