animalize

导航

【转载】递归正则表达式的一般构造方法

标题:递归正则表达式的一般构造方法

作者:xhd2015

原帖:http://tieba.baidu.com/p/4117059926

=======================

 

先说说问题吧,很老套,如何匹配嵌套的<>

 

如果你能匹配

class regex<>

恭喜你,最初级的会了,往下看


那么,换成这个

class regex<class<>>

如果你只匹配到红色字符,不幸,你错了

一般表达式对于嵌套的符号对是没有效果的

 

并不是所有的正则工具都支持递归,实现递归的关键是能对 “规则”引用。

没错,对规则引用(而不是对\1之类的捕获组的反向引用)

如果规则允许嵌套,就意味着允许递归。先看看什么是规则引用,以及和捕获组的反向引用的区别:

表达式 (\s|\w) 意味着 或者\s,或者\w,加上括号以后,就有一个组编号,假设编号为1,那么,

规则引用就是 (?1)

反向引用就是 \1 没有括号

区别是,规则引用表示将那个表达式完整地应用在这里,因此(\s|\w)(?1)等价于(\s|\w)(\s|\w)

而捕获组的反向引用就是简单地将匹配到的字符完整地copy到此处

 

现在进入正题,规则引用怎么构造递归正则?

前面说了规则引用是递归的关键,这句话是什么意思呢?

递归就是自身包含自身,所以,如果规则自身包含自身,那么这就是递归。而很多嵌套的字符串其实也是一种递归。

对于嵌套<>,一般的规则只能匹配有限深度的<>,下面讨论几种情况

匹配1深度 <[^<>]*>

匹配深度2 <[^<>]*<[^<>]*>[^<>]*>

匹配深度3 ……

如果亲自动手写一写1-3的深度,你就会发现规则很简单

我们发现,2是由1递归生成的,因此,我们尝试从2中删除1,用___替代,得到

<[^<>]*___[^<>]*>

这里,特殊性可以代表一般性,所以递归式是

Rn= <[^<>]*Rn-1[^<>]*>

所以,递归表达式就是

(<[^<>]*(?1)*[^<>]*>)

经检验,完全正确。(?1)后面加个*表示同一深度允许有0个或多个<>对。

 

一般性方法:(小菜都会)

1.写出深度1的嵌套表达式

2.写出深度2的嵌套表达式

3.用(?n)替换2中1的位置,就是整个递归表达式。(n是所在组的编号)

这个方法是算法化的,可以由软件实现,即给出符号对,可以生成递归正则

 

=======================

转载者注

(<[^<>]*(?1)*[^<>]*>)可以这么写:

<[^<>]*(?0)*[^<>]*>

其中(?0)表示对整个表达式的递归引用

 

再举一例,匹配嵌套类定义,如:
class regex<
class innerA<
class innerC<
>
>
class innerB<
>
>
正则式:\s*class(?:\s+\w+)?<(?:(?0)|\s)*>\s*

posted on 2016-04-06 14:39  animalize  阅读(2629)  评论(0编辑  收藏  举报