文章原文https://white-night.club/index.php/2023/04/23/study12/
在之前我们提到过正则文法RG的定义:左部为语法变量,右部为语法变量或语法变量与字符串的连接。例子如下(大写字母表示语法变量):
A→B | A→ωB | A→B
而除了用正则文法描述单词外,还可以用正则表达式(regular expression)来描述单词。
正则表达式的定义
与正则文法等价
给定一个字母表Σ,则它的正则表达式有:
- Ø 表示空集
- ε 表示空字符串集合 { ε }
- 对应任意字母表中的一个字符a,所得的正则表达式为它本身,即 a。
- 如果r和s都是Σ上的正则表达式,那么有:
- r | s也是Σ上的正则表达式,“|”表示或。
- r · s也是Σ上的正则表达式,“·”表示连接,一般可以省略不写。
- r*也是Σ上的正则表达式,“*”表示克林闭包。
而正则表达式代表的语言或集合则被称为正则集(regular set)。
直接给个例子,比如字母表Σ={a,b},那么它的正则表达式以及正则表达式表示的集合有:
- 正则表达式:a|b
- 正则集:{a,b}
- 正则表达式:aa|bb
- 正则集:{aa,bb}
- 正则表达式:(a)(a|b) 等价于 aa|ab
- 正则集:{aa,ab}
- 正则表达式:a*
- 正则集:{ε,a,aa,aaa,…}
- 正则表达式:(a|b)*
- 正则集:{ε,a,b,aa,bb,ab,abbbb,…}(由a和b构成的字符串的集合)
正则表达式的代数定律
常用于其等价变换
综上我们可以看到,正则表达式还满足一些代数定律:
- 或符号 |
- 满足交换律 r|s=s|r
- 满足结合律 r|(s|t)=(r|s)|t
- 连接符号 ·
- 满足结合律 (rs)t=r(st)
- 对于或符号满足分配律 r(s|t)=rs|rt
- 克林闭包符号 *
- 满足 r*=(r|ε)*
- 满足幂等关系 r**=r*
其中,正则表达式还满足以下规则:
- 克林闭包与正闭包之间的转换
- r*=r+|ε (克林闭包比正闭包多一个空字符串ε的体现)
- r+=r*r=rr* (表示的集合中的字符串,至少由一个r组成)
- 符号 ?,表示“0或一个”
- r?=r|ε。其表示的集合为{ε,r}
- 字符类,使用方括号[ ]简写正则表达式
- [a-z]表示正则表达式 a|b|c|d|e|…|z
- [0-9]表示正则表达式0|1|2|…|9
- [A-Za-z][A-Za-z0-9]*表示正则表达式 (A|…|Z|a|…|z)(A|…|Z|a|…|z|0|…|9)*。该正则表达式可以用来描述标识符的集合(其中标识符不能以数字开头)。
正则表达式↔正则集
相关例题
我们整两个课后习题巩固下相关知识。
先来道从正则表达式→正则集的:
给定正则表达式 ((ε|0)1*)* ,求其正则集
先看最外层,克林闭包大致表示:字符的无限种组合。那么最外层的克林闭包符号不如向括号内移,得到
((ε|0)*1*)* (其中1**=1*)
发现(ε|0)*可以等价为0*。继续得到
(0*1*)*
到这就很明显了,该正则表达式表示的集合:由0和1构成的字符串,其中包括空字符串ε。其正则集为
{ε,0,1,001,011,…} 或 {x|x是0和1构成的字符串,包括ε}
形式语言与自动机
额外拓展
接上面,再来个正则集→正则表达式的例题:
给定正则集 {x|x∈{0,1}+ & x中不含有形如10110的子串},求其正则表达式。
很明显,你直接想是很难想出来该怎么写的,得画状态转换图。但这块的知识在《形式语言与自动机》中,所以建议各位先看网课自学并掌握以下内容:
- 状态消除法–将状态转换图化为正则表达式。
- 怎么画状态转换图?状态转换图表达的含义是什么?
言归正传,在本题中,你应该能得出这个状态转换图
q0-q4的状态转换图
- 图的入度(或入边):表示“向其指向的图输入某个值”。
- 图的出度(或出边):表示“向其指向的图输出某个值”。
- 边上的字符:表示输入或输出的值。
- 图自己指向自己:表示克林闭包。如图中的q0→q0,表示q0向q0输出(0*).
接下来是利用状态消除法将该图化为正则表达式,状态消除法的规则如下:
- 向图中添加起始点和终点,并设置读入/读到空字符串ε。不然最后消去所有节点后图就是空白的了。
- 找到某个要消去的节点(假设为q4)
- 忽略其自己指向自己的边。然后计算它的出度n和入度m(q4入度为1;出度为1)
- 去掉该节点以及和它相连的所有边。并在图中的某个节点上补充m*n条边。
对于该题,我们已经有了它的状态转换图,接下来就是将它转换为正则表达式。
写者注
附:作图的时候忘记加双层圆了,实际上q0-q4这五个节点都应该加上双层圆。表示“自动机可以在该节点终止”。具体的建议各位自行了解。
将其转换为正则表达式,我们需要对图中的每个“终止状态”,通过状态消除法,添加起始点和终点求解正则表达式。
以该图为例,先以q0为终止状态,添加对应的终点。(可能缺点细节,但不影响)
以q0为终点
然后消去q4。分析q4的入度和出度:
- 入度:q3-q4
- 出度:q4-q1
可见我们需要补上m*n,即一条边。所补的边应该是q3-q1。
从q3到q1,需要经过1→1*→1。所以q1应该读入11*1。得到图为
去掉q4
接着我们去掉q3,它的出入度情况为
- 入度:q2-q3
- 出度:q3-q2 q3-q1
说明我们需要补两条边,分别是:q2-q2,q2-q1。
q2读入10,转入状态q0;q2读入1-11*1-1*,即111*11*,转入状态q1,所得状态图为:
去掉q3
接下来去掉q2,和上面过程一样,得到图:
去掉q2
接下来就是去掉q1了,得到图:
去掉q1
现在只剩q0。很明显,把q0去掉,所得到的结果就是q0为终点的正则表达式。结果如下
(0+1(1+0(10)*(111*11*))*(0(10)*0))*
当然,根据你去掉节点顺序的不同,最后得到的结果也不同。但这些结果之间是等价的、可以相互转换的.
然后再对q1-q4这几个节点做相同的操作,最后得到的正则表达式相加便是结果。(但这过程太长;而且说实话,想了下我写的q0确实等价于答案给的q0,但我忙活半天,这纸质过程真写不出来。所以这里直接放结果了)。
标签:编译原理