简单正则表达式实现引擎

原创 2008年09月30日 12:16:00
  1. /* match: search for regexp anywhere in text */ 
  2. int match(char *regexp, char *text) {         
  3.     if (regexp[0] == '^')   
  4.         return matchhere(regexp+1, text);  
  5.         
  6.     do {   
  7.         /* must look even if string is empty */   
  8.         if (matchhere(regexp, text))    
  9.             return 1;        
  10.     } while (*text++ != '/0');   
  11.     
  12.     return 0;  
  13. }  
  14. /* matchhere: search for regexp at beginning of text */ 
  15. int matchhere(char *regexp, char *text) {   
  16.     if (regexp[0] == '/0')           
  17.         return 1;         
  18.     if (regexp[1] == '*')    
  19.         return matchstar(regexp[0], regexp+2, text);    
  20.     if (regexp[0] == '$' && regexp[1] == '/0')     
  21.         return *text == '/0';     
  22.     if (*text!='/0' && (regexp[0]=='.' || regexp[0]==*text))    
  23.         return matchhere(regexp+1, text+1);     
  24.     return 0;   
  25. }   
  26. /* matchstar: search for c*regexp at beginning of text */    
  27. int matchstar(int c, char *regexp, char *text) {   
  28.     do {
  29.         /* a * matches zero or more instances */   
  30.         if (matchhere(regexp, text))     
  31.             return 1;       
  32.     } while (*text != '/0' && (*text++ == c || c == '.'));  
  33.     
  34.     return 0;    
  35. }

这一小段代码就是c语言实现的简单的正则表达式引擎,虽然简单,但是包含了大部分日常运用到的功能。

 

解释:

函数match(regexp,text)用来判断文本中是否出现正则表达式;如果找到了一个匹配的正则表达式则返回1,否则返回0。如果有多个匹配的正则表达式,那么函数将找到文本中最左边的并且最短的那个。

match函数中的基本操作简单明了。如果正则表达式中的第一个字符是^(固定位置的匹配),那么匹配就一定要出现在字符串的开头。也就是说,如果正则表达式是^xyz,那么仅当xyz出现在文本的开头而不是中间的某个位置时才会匹配成功。在代码中通过把正则表达式的剩余部分与文本的起始位置而不是其他地方进行匹配来判断。如果第一个字符不是^,那么正则表达式就可以在字符串中的任意位置上进行匹配。在代码中通过把模式依次与文本中的每个字符位置进行匹配来判断。如果存在多个匹配,那么代码只会识别第一个(最左边的)匹配。也就是说,如果则在表达式是xyz,那么将会匹配第一次出现的xyz,而且不考虑这个匹配出现在什么位置上。

注意,对输入字符串的推进操作是在一个do-while循环中进行的,这种结构在C程序中使用相对较少。在代码中使用do-while而不是while通常会带来疑问:为什么不在循环的起始处判断循环条件,而是在循环末尾当执行完了某个操作之后才进行判断呢?不过,这里的判断是正确的:由于*运算符允许零长度的匹配,因此我们首先需要判断是否存在一个空的匹配。

大部分的匹配工作是在matchhere(regexp,text)函数中完成的,这个函数将判断正则表达式与文本的开头部分是否匹配。函数matchhere把正则表达式的第一个字符与文本的第一个字符进行匹配。如果匹配失败,那么在这个文本位置上就不存在匹配,因此matchhere将返回0。然而,如果匹配成功了,函数将推进到正则表达式的下一个字符和文本的下一个字符继续进行匹配。这是通过递归地调用matchhere函数来实现的。

由于存在着一些特殊的情况,以及需要设置终止递归的条件。因此实际的处理过程要更为复杂些最简单的情况就是,当正则表达式推进到末尾时(regexp[0] == '/0'),所有前面的判断都成功了,那么这个正则表达式就与文本匹配。

如果正则表达式是一个字符后面跟着一个*,那么将会调用matchstar来判断闭包(closure)是否匹配。函数matchstar(c, regexp, text)将尝试匹配重复的文本字符c,从零重复开始并且不断累加,直到匹配text的剩余字符,如果匹配失败,那么函数就认为不存在匹配。这个算法将识别出一个“最短的匹配”,这对简单的模式匹配来说是很好的,例如grep,这种情况下的主要问题是尽可能快地找到一个匹配。而对于文本编辑器来说,“最长的匹配”则是更为直观,且肯定是更好的,因为通常需要对匹配的文本进行替换。在目前许多的正则表达式库中同时提供了这两种方法,在《The Practice of Programming》一书中给出了基于本例中matchstar函数的一种简单变形,我们在后面将给出这种形式。

如果在正则表达式的末尾包含了一个$,那么仅当text此时位于末尾时才会匹配成功:

    if (regexp[0] == '$' && regexp[1] == '/0')

        return *text == '/0';

如果没有包含$,并且如果当前不是处于text字符串的末尾(也就是说,*text!='/0')并且如果text字符串的第一个字符匹配正则表达式的第一个字符,那么到现在为止都是没有问题的;我们将接着判断正则表达式的下一个字符是否匹配text的下一个字符,这是通过递归调用matchhere函数来实现的。这个递归调用不仅是本算法的核心,也是这段代码如此紧凑和整洁的原因。

如果所有这些匹配尝试都失败了,那么正则表达式和text在这个位置上就不存在匹配,因此函数matchhere将返回0。

在这段代码中大量地使用了C指针。在递归的每个阶段,如果存在某个字符匹配,那么在随后的递归调用中将执行指针算法(例如,regexp+1 and text+1),这样在随后的函数调用中,参数就是正则表达式的下一个字符和text的下一个字符。递归的深度不会超过匹配模式的长度,而通常情况下匹配模式的长度都是很短的,因此不会出现耗尽内存空间的危险。

自己动手写一个轻巧,高效的正则表达式引擎

http://www.graphviz.org/ 下面两张表是两种正则表达式引擎的表现。其中一种用在许多语言的标准解释器,有Perl。另外一种用在为数不多的地方,主要是awk和grep。这两种引擎有...
  • kingoverthecloud
  • kingoverthecloud
  • 2015年01月25日 21:55
  • 3300

实现最简单的正则表达式

/* 原题:“在一篇英文文章中查找指定的人名,人名使用二十六个英文字母(可以是大写或小写)、空格以及两个通配符组成(*、?),通配符“*”表示零个或多个任意字母,通配符“?”表示一个任意字母。 如...
  • CodeArhat
  • CodeArhat
  • 2011年09月27日 08:49
  • 910

re2正则表达式引擎学习(一)

re2是Google公司开发的一款正则表达式引擎。可以实现正则表达式的匹配,且比较小巧,开源,适合学习 主要想将re2的正则表达式匹配过程移植到GPU上,在GPU上实现正则表达式的匹配,提高匹配的速...
  • tianfengbing
  • tianfengbing
  • 2015年07月29日 10:59
  • 815

正则表达式的回溯机制

正则表达式的引擎分析 正则表达式的引擎有两个特点: 1.默认情况下都是贪婪匹配。 2.引擎总是着急的,会返回最先匹配到结果 正则引擎的工作原理举例: 当把cat应用到“He ca...
  • bkcnl
  • bkcnl
  • 2017年06月28日 09:43
  • 202

正则表达式原理及引擎简化递归实现

转载请注明作者:phylips@bmy 出处:http://duanple.blog.163.com/blog/static/7097176720098303134160/   概述 ...
  • Bluesilence
  • Bluesilence
  • 2014年09月17日 21:39
  • 1110

正则表达式: NFA引擎匹配原理

NFA引擎匹配原理 1       为什么要了解引擎匹配原理 一个个音符杂乱无章的组合在一起,弹奏出的或许就是噪音,同样的音符经过作曲家的手,就可以谱出非常动听的乐曲,一个演奏者同样可以照着乐谱奏...
  • qinyushuang
  • qinyushuang
  • 2015年02月12日 11:33
  • 1305

简单的正则表达式引擎

1、基础理论 非确定有限自动机(NFA),是计算理论中抽象出来的状态机计算模型。它拥有有限个状态,当前状态根据不同的输入可以迁移到其他的状态,它的下一个状态不是唯一确定的。 正则表达式本身是有限长度的...
  • u012637838
  • u012637838
  • 2014年11月18日 13:27
  • 1776

c实现极简单的正则表达式解析

c实现极简单的正则表达式解析 define 头文件 ///////////////////////////////////define 头文件///////////////////////...
  • ppdyhappy
  • ppdyhappy
  • 2015年08月19日 11:10
  • 723

一个正则表达式引擎的设计和实施1-汤普森构造

本节开始,我们要解决的算法题是如何设计一个正则表达式引擎,正则表达式在字符串处理中,几乎是最为复杂的一部分。在一般的算法面试中,要你用代码写出整个引擎的可能不高,但是要求你描述相关算法倒是可能的,因此...
  • tyler_download
  • tyler_download
  • 2016年11月05日 16:02
  • 909

简单功能的正则表达式引擎实现

功能非常简单,只是检查 text 的前缀是否与 reg_exp 匹配,并不去检查 text 中间是否有与 reg_exp 匹配的子串。 纯递归实现...
  • fly1183989782
  • fly1183989782
  • 2015年10月20日 10:43
  • 292
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:简单正则表达式实现引擎
举报原因:
原因补充:

(最多只允许输入30个字)