浅谈正则表达式背后的基本原理

一、写在前面

搞编程的都知道正则表达式是什么东西,这里就不多啰嗦了,需要强调的是,这篇文章并不是教你怎么去使用用正则表达式,正则表达式的语法并不是本文的重点,这篇文章的目的就是剥开正则表达式的语法糖,来看一看正则表达式最本质的原理,如果文章中有错误或者纰漏,欢迎批评指正。

二、什么是语法糖

在上面我提到了语法糖的概念,也许有人还不清楚语法糖是什么东西,这里简单的说一下。

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。——摘自 百度百科

可以这么说吧,像C、C++、Java等等这些编程语言都可以看做成语法糖,因为最终还是得将这些高级程序语言翻译成机器代码,也就是10101……这样的形式,要知道所有的可执行程序最终都可以只需要赋值跳转两种结构即可,而高级语言都是对这两种结构的封装,来适应不同的应用场景,除了机器代码,汇编和这些高级语言都是语法糖,一层一层的包装,达到简化开发的目的,大家想想,如果没有这些语法糖,那我们岂不是得天天用机器代码写程序?

三、算数表达式

这里先引入一个小小的例子,我想在阅读这篇文章的人都知道什么是算数表达式,最基本的算数表达式:

1,2,3,4,5,6,7,8,9,0,……
+,-,*,/,……

这些都是最基本的算数表达式,而由这些最基本的算数表达式可以构造出更加复杂的复合表达式比如1+1,3*5等等,无论是基本的还是复合的,它们都是算数表达式,通过这个例子,来自然的过渡到下面正则表达式的内容,其实本质上算数表达式和正则表达式的道理是差不多的。

四、正则表达式

构成正则表达式最基本的就是给定的字符集∑={c1,c2,c3,……,cn},这就相当于算数表达式中的0,1,2,3……这些基本算数表达式。
接下来呢,就是他的归纳定义,来告诉我们如何通过最基本的字符集构造出复杂的正则表达式:

  1. 空串ε是正则表达式。
  2. 对于任意字符c∈∑,c是正则表达式
  3. 如果M,N是正则表达式,则以下也是正则表达式:

    
    **选择**  M|N = {M,N}
    **连接**  MN  = {mn | m∈M, n∈N}
    **闭包**  M*  = {ε,M,MM,MMM,……}
    

不难看出,以上的归纳定义给出了正则表达式最基本的的形式,无论多么复杂的正则表达式都是在这个基础上构成的。

现在我们通过一个小例子来加深对上面概念的理解:


给定一个字符集∑={a,b},可以写出那些正则表达式呢?
1.  ε
2.  a,b
3.  ε|ε,ε| a , ε| b ,……
4.  εa , εb , ab , εε , ……
5.  a(ε| a) , b(ε|b),……
6.  ε* , (a(ε| a))*,……
7.  ……

也就是说,单个的字符都是正则表达式,它们按照上面的定义组合起来依然是正则表达式,正则表达式与正则表达式相互组合又可以生成新的正则表达式,在复杂的正则表达式都是由这些基本的正则表达式构成,当然了上面这些只是该字符集的正则表达式的一小部分,因为这个字符集的正则表达式集合是一个无限集,到这里,我想大家应该有所体会。

我们再来看一个例子:


我们用上面的正则表达式的概念来构造出用来描述C语言标识符的正则表达式:
首先给定字符集,我们都知道C语言的字符集有ASCII码构成。
C语言标识符的格式:以字母或下划线开头,后面跟零个或多个字母、数字或下划线。

该怎么用正则表达式来描述呢?

(a|b|c|……|z|A|B|C|……|Z|_)(a|b|c|……|z|A|B|C|……|Z|0|1|2|3|……|9|_))*

首先来看,这个正则表达式是由两个子表达式连接而成,每个子表达式都是用选择符|构成,又因为第二个子表达式可以出现零或多次,所以加上闭包,是不是看的脑袋都大了,是不是觉得平时什么时候这么写过正则表达式,下面就得说说语法糖的作用啦。

五、正则表达式中的语法糖

大家接触到的正则表达式的语法似乎是有差异的,比如POSIX风格正则表达式和Perl风格正则表达式,要知道无论什么风格的正则表达式它们背后的原理都是一样的,只是在上层提供的语法糖不一样而已,实际应用的过程中都是根据上面的原理演变过来的,语法糖可以大大简化正则表达式的形式,变得更容易阅读和理解,就像下面的对应关系一样。

[c1-cn] == c1|c2|c3|……|cn

e? == ε|e

e+ == (e*)\ε

e{i,j} == i到j个e连接

这里就不一一举例了,无论上面的对应关系中左边的语法如何变化,它所对应的右边的基本原理都是一样的。

六、小结

正则表达式可以写的非常复杂,复杂到除了作者外很少有人看的懂的,曾经我也是一度不能自拔,但随着学习的深入,慢慢的发现,剥开正则表达式表面的东西,去看背后的原理,才有一种恍然大悟的感觉。

你可能感兴趣的