【转载】递归正则表达式的一般构造方法
标题:递归正则表达式的一般构造方法
作者: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) 编辑 收藏 举报