基于‘DFA’的使用‘表驱动法’识别‘字符串模式’的方法

一、概述

1. 术语简介

1)DFA

Deterministic Finite Automata,确定的有穷自动机,这是一个识别字符串模式的模型,术语参考自书籍《编译原理》。

该模型对应一个状态,字母表,和转换函数的集合。

例如:需要识别字符串aabb

状态:当前字符串识别的状态,在例子中,其中的,a,aa,aab,aabb对应不同的状态,假设对应为状态1,2,3,4,其中4被称作接受状态(accept state,表示已经得到符合模式的字符串)

字母表:字符串中需要进行识别字符集合,在例子中,a和b是需要识别的字符,字母表为{a,b}

转换函数:描述了每个状态在字母表中每个字母对应的下一个状态,如F[1, a] = 2,F[1, b] = error

为方便举例,上述使用了某个具体的字符串说明相关概念,实际上DFA可以识别字符串的集合,它的识别能力等价于使用正则表达式描述的字符串的集合。

2)表驱动法

每个DFA模型(状态,字母表,以及转换函数的集合)可以表示为一张转换表,表中的每行对应一个状态,表中的每列对应字母表中的字符,对应于上述的例子,在下表中,0状态表示从此处开始识别,err表示识别到一个错误(即当前字符串不符合模式),acc表示识别成功,接受状态用“()”标识,如下表所示:

                                                                  表1.1 aabb的DFA对应的转换表

 abeof
01errerr

1

2errerr
2err3err
3err4err
(4)errerracc

表驱动法是以DFA对应的这张表,构造出一个“用表去驱动字符串模式的识别”的方法。

3)字符串模式

字符串模式表示一个字符串的集合,熟悉正则表达式的话可以将他们看做同一事物,识别以“.txt”结尾的开头为a或b或c的字符串,可以使用模式,"(a|b|c)\.txt",表示。(该模式用正则表达式表示,"."表示在正则表达式中有特殊含义:表示任意一个字符,使用"\"将它转义为一般字符)

2. 问题描述

在编译原理课程上,老师布置了一个任务:用表驱动法模拟DFA的识别字符串(语言):"(a|b)*abb",的过程。

(该模式用正则表达式表示,"*"表示前面的符号存在0次或多次)

二、算法思路

根据上述的介绍,实际上需要做的工作是:

1)将需要识别的字符串表示为DFA

2)将DFA转变为相应的转换表

3)根据转换表实现表驱动法

由于该算法的重心在于实现表驱动法,所以前两步在纸上完成,先根据《编译原理》书籍上提到的相关算法(为字符串构造NFA(Non-deterministic Finite Automata,不确定的有穷自动机),将NFA转化为DFA,最小化DFA的状态)构造出表示"(a|b)*abb"的DFA,然后描述出对应的转换表,如下图所示:

图2.1 "(a|b)*abb"对应的转换图

 abeof
010err
112err
213err
(3)10acc

                                              图2.2 "(a|b)*abb"对应的转换表

根据转换表,表驱动法可以用伪代码描述如下,参考自《编译原理》:

s = s0    // s0 is state 0, the beginning state
c = nextChar()
while (c != eof){
    s = F(s, c)    // F is the state-transition method
    c = nextChar()
}
if (s in acceptState())    // whether exit state s is accept state when read eof
    print("yes")
else
    print("no")

三、算法实现

1. C++实现代码

#include <iostream>    // for cin, cout
#include <map>    // for map

using std::cin;
using std::cout;
using std::map;

// the enumeration of DFA states
enum state {S0=0, S1, S2, S3 ,ERR};

// the max row and colum of transition-table
const int MAXROW = 5;
const int MAXCOL = 3;
//===----------------------------------------===//
//  state-transition table definition
//          a   b
//     S0  S1  S0
//     S1  S1  S2
//     S2  S1  S3
//     S3  S1  S0
//    ERR ERR ERR
//===----------------------------------------===//
// the first column set for invalid char that not in the alphabet
state transTable [MAXROW][MAXCOL] =
{
    {  ERR,  S1,  S0  },
    {  ERR,  S1,  S2  },
    {  ERR,  S1,  S3  },
    {  ERR,  S1,  S0  },
    {  ERR, ERR, ERR  }
};
// the map table for alphabet of (a|b)*abb
map<char, int> alphabet =
{
    // 'a' map to the 1 column and 'b' map to the 2 column of transTable
    { 'a' , 1 },
    { 'b' , 2 }
};

void tableDrive();    // table-drive function
state F(state, char);    // state-transition function
char nextChar();    // get next input char

int main()
{
    cout << "================================\n";
    cout << " String-model: (a|b)*abb        \n";
    cout << " End-of-input: $                \n";
    cout << "================================\n";
    while (1){
        cout << ">";
        tableDrive();
    }
    return 0;
}

// table-drive function for recognize the string-model:(a|b)*abb
void tableDrive()
{
    state s = S0;
    char c = nextChar();
    while (c != '$'){    // '$' indicate the end of input
        s = F(s, c);
        c = nextChar();
    }
    // S3 is the only accept state
    if (s == S3)
        cout << "yes\n";
    else
        cout << "no\n";
}
//===----------------------------------------===//
//  state-transition function
//  s is the current state, c is the current char
//  base on the transition-table above of DFA
//===----------------------------------------===//
state F(state s, char c)
{
    state ret;
    int col = alphabet[c];    // if c not in alphabet, the maped value will set to 0

    ret = transTable[s][col];
    return ret;
}
// get the next input char
char nextChar()
{
    char ret;

    cin >> ret;
    return ret;
}

2. 运行结果

图3.1 运行结果

四、小结

可以发现,通过DFA的转换表来完成字符串模式的识别是相当直观的,这个识别工作可以用作编译器的词法分析。

 

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值