实现正则表达式处理功能

 本来要打算每一个星期争取能够写一篇文章的,但是的确我自己有些懒散,MSN的空间不能在文档里面插入图片,又给了我一个绝好的偷懒的借口。就好必喜欢在 下雨天睡懒觉一样,总是找着诸如“太阳还没有起床”之类的借口。还有一个借口就是,我要写一些自己原创,或者是自己懂得文章,不能随便google一篇文 章,引用一下敷衍了事。更要命的是,文章还需要长一些的。写完以后,不管内容怎么样,总是要自己好好满足一把。感觉就像以前看到钱钟书书里面写过的一个 人,自己写文章写着写着,觉得写到妙处了,就朝着镜子里的自己深深的鞠一躬:“XX先生,我真的是很佩服你能写出这么好的文章出来”。 好了,废话少说,我们经如正题,今天我要说的是:实现一个基本的正则表达式分析器,这个分析器可以处理*、+、?、()、等操作符。是的,这个正则表达 式的确有些寒碜,不过至少知道原理了,也不枉此行那……

在介绍正则表达式之前,我先说一下有限自动机的概念,呃,先举个例子吧,请看代码:

#include
#include

using namespace std;

enum TokenType
{
BOOM_ERROR = -1, // 啊哈,出错了
NUMBER = 1,
IDENTIFIER = 2,
IF = 4
};

int DFA_Table[][37] = {
// 0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z !
{1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,-1}, // s0 -- 起始状态
{1,1,1,1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // s1 -- 到这里说明是数字
{3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,-1}, // s2 -- 变量
{2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,-1},
{2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,-1} // s4 -- 这是IF
};

//
// Match:
// 给定一个字符串str,判断这个字符串的类型
//
// 例子:
// if, 返回IF
// 数字,返回NUMBER
// 变量,返回IDENTIFIER
//
TokenType Match(string str)
{
int state = 0;

for (string::iterator iter = str.begin();
iter != str.end();
++iter ) // 这里可能有人不太习惯,为什么用++iter,而不用大多数人都习惯的iter++
// 因为iter++先将iter的值返回,再执行++,这里就涉及到一个拷贝操作,如果你的iter是一个非常大的变量
// 性能会受到一些影响,但是++iter只执行++操作
{
char c = *iter;
int index = 0;
if ( c >= '0' && c <= '9' )
{
index = c - '0';
}
else if (c >= 'a' && c <= 'z')
{
index = c - 'a' + 10; // a列在DFA_Table中的索引值
}
else
{
index = 36; // !列在DFA_Table中的索引值,到这里说明不匹配了
}

state = DFA_Table[state][index];

if (state == BOOM_ERROR)
break;
}

return (TokenType)state;
}

int g_line = 0;
void Print(TokenType type)
{
switch (type)
{
case BOOM_ERROR:
cout << ++g_line << ": BOOM_ERROR/n" <<>
break;

case IF:
cout << ++g_line << ": IF/n" <<>
break;

case NUMBER:
cout << ++g_line << ": NUMBER/n" <<>
break;

case IDENTIFIER:
cout << ++g_line << ": IDENTIFIER/n" <<>
break;

default:
cout << ++g_line << ": Error/n" <<>
break;
}
}

int main()
{
Print(Match("if"));
Print(Match("iff"));
Print(Match("if0"));
Print(Match("0if"));
Print(Match("i0f"));
Print(Match("ia"));
Print(Match("01"));
Print(Match("123"));
Print(Match("1f"));
Print(Match("abcd"));
Print(Match("ab"));
Print(Match("a"));
Print(Match("0"));
Print(Match("i"));
Print(Match("_"));

return 0;
}

例子1:一个简单的DFA表驱动匹配程序

上面的例子里,字符串的匹配或者说是分类是通过有限自动机来完成的,有限自动机在代码里面的表示就是那个二维数组 DFA_Table。DFA_Table的每一行(DFA_Table[i])表示有限自动机的状态,而列表示从当前状态可以执行的状态转换(Transfer)。例如在匹配的时候,程序先从DFA_Table[0],也就是起始状态开始,如果第一个字符串是i,则根据DFA_Table[0]['i']指定的转换规则跳转到下一个状态(State)去,这里下一个状态是2,也就是DFA_Table的第三行,再根据str的下一个字符来确定要转换的状态。匹配过程一直循环到字符串被全部处理掉,这时程序判断当前的状态是不是一个可以接受的状态(Acceptable State),也就是说这个状态是否在TokenType中定义,如果状态在TokenType中定义,那好,我们给出的字符串匹配成功,否则……BOOM。

我在Match函数的for循环中用了if判断来根据当前的字符选择正确的索引,其实如果你不嫌麻烦的话,你的Match函数中的for循环可以简化成这样:

for (string::iterator iter = str.begin();
iter != str.end();
++iter )
{
state = DFA_Table[state][*iter];
}

前提是愿意把DFA_Table扩展成一个127 * 5的二维表格。

未完待续……
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值