正则表达式基础与学习03----来自《编译原理与实践》

 在下面的示例中,被匹配的串通常是英语描述,其任务是将描述翻译为正则表达式。包含
了记号描述的语言手册是编译器的程序员最常见的。偶尔还需要变一下,也就是将正则表达式
翻译为英语描述,我们也有一些此类的练习。
例2.1 在仅由字母表中的3个字符组成的简单字母表å = {a, b, c}中,考虑在这个字母表上的仅
包括一个b 的所有串的集合,这个集合由正则表达式
( a | c ) * b ( a | c ) *
产生。尽管b出现在正则表达式的正中间,但字母b 却无需位于被匹配的串的正中间。实际上,
在b 之前或之后的a 或c 的重复会发生不同的次数。因此,串b、a b c、a b a c a、b a a a a c、c c b a c a
和ccccccb 都与上面的正则表达式匹配。
例2.2 在与上面相同的字母表中,如果集合是包括了最多一个b 的所有串,则这个集合的正则
表达式可通过将上例的解作为一个解(与那些仅为一个b 的串匹配),而正则表达式( a | c ) *
则作为另一个解(与b 根本不匹配)来获取。因此有以下解:
( a | c ) * | ( a | c ) * b ( a | c ) *
下面是一个既允许b 又允许空串在重复的a 或c 之间出现的另一个解:
( a | c ) * ( b | ) ( a | c ) *
本例引出了正则表达式的一个重要问题:不同的正则表达式可生成相同的语言。虽然在实际中
从未尝试着证实已找到了“最简单的”,例如最短的,正则表达式,但通常总是试图用尽可能
简单的正则表达式来描述串的集合。这里有两个原因:首先在现实中极少有标准的“最短的”
解;其次,在研究用作识别正则表达式的方法时,那儿的算法无需首先将正则表达式简化就可
将识别过程简化了。
例2.3 在字母表å= {a, b}上的串S的集合是由一个b及在其前后有相同数目的a 组成:
S = { b, aba, aabaa, aaabaaa, . . . } = { an b an | n≠0 }
正则表达式并不能描述这个集合,其原因在于重复运算只有闭包运算*一种,它允许有任意次
的重复。因此如要写出表达式a * b a *(尽可能接近地得到S的正则表达式),就不能保证在b 前
后的a 的数量是否相等了,它通常表示为“不能计算的正则表达式”。但若要给出一个数学论
证,则需使用有关正则表达式的称作P u m p i n g引理(Pumping lemma)的著名定理,这将在自
动机理论中学到,现在就不谈了。
很明显,并非用简单术语描述的所有串都可由正则表达式产生,因此为了与其他集合相区
分,作为正则表达式语言的串集合称作正则集合( regular set)。非正则集合偶尔也作为串出现
在需要由扫描程序识别的程序设计语言中,通常是在出现时才处理它们,我们也将其放在扫描
程序一节中讨论。
例2.4 在字母表å= {a, b, c}上的串S中,任意两个b 都不相连,所以在任何两个b 之间都至
少有一个a 或c。可分几步来构造这个正则表达式,首先是在每一个b 后都有一个a 或c,它
写作:
( b ( a | c ) ) *
将其与表达式( a | c ) *合并,( a | c ) *是与完全不包含b 的串匹配,则写作:
( ( a | c ) * | ( b ( a | c ) ) * ) *
或考虑到( r * | s * ) *与( r | s ) *所匹配的串相同,则:
( ( a | c ) | ( b ( a | c ) ) ) *

( a | c | b a | b c ) *
(警告!这还不是正确答案)。
这个正则表达式产生的语言实际上具有了所需的特性,即:没有两个相连的b(但这还不正
确)。有时需要证明一下上面的这个说法,也就是证明在L(( a | c | b a | b c ) *)中的所有串都不包
括两个相连的b。该证明是通过对串长度(即串中字符数)的归纳实现的。很显然,它对于所有
长度为0、1和2的串是正确的:这些串实际是串、a、c、a a、a c、c a、c c、ba 和b c。现在假设
对于在长度i < n 的语言中的所有串也为真,并令s 是长度为n > 2 的语言中的一个串,那么s 包
含了至少一个上面所列的非的串,所以s = s1s2,其中s1 和s2 也是语言中的非串。通过假设归
纳,证明了s1 和s2 都没有两个相连的b。因此要使s 本身包括两个相连的b 的唯一方法是使s1 以
一个b 结尾,而s2 以一个b 开头。但又因为语言中的串都不以b 结尾,所以这是不可能的。
论证中的最后一个事实,即由上面的正则表达式所产生的串都不以b 结尾,也显示了我们
的解还不太正确:它不产生串b、a b和c b,这3个都不包括两个相连的b。可以通过为其添加一
个可选的结尾b来修改它,如下所示:
( a | c | b a | b c ) * ( b | )
这个正则表达式的镜像也生成了指定的语言:
( b| ) ( a | c | a b | c b ) *
以下也可生成相同的语言:
(n o t b|b notb ) * ( b | )
其中n o t b = a | c。这是一个使用了下标表达式名字的例子。由于无需将原表达式变得更复杂就
可使n o t b的定义调整为包括了除b 以外的所有字符,因此实际是在字母表较大时使用这个解。
例2.5 本例给出了一个正则表达式,要求用英语简要地描述它生成的语言。若有字母表å =
{a, b, c},则正则表达式:
( ( b | c ) * a ( b | c ) * a ) * ( b | c ) *
生成了所有包括偶数个a 的串的语言。为了看清它,可考虑外层左重复之中的表达式:
( b | c ) * a ( b | c ) * a
它生成的串是以a 结尾且包含了两个a(在这两个a 之前或之间可有任意个b 和c)。重复这些串
则得到所有以a 结尾的串,且a 的个数是2的倍数(即偶数)。在最后附加重复(b | c)*(如前
例所示)则得到所需结果。
这个正则表达式还可写作:
(n o t a* a nota* a)* n o t a*
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lujunql

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值