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

Posted animalize

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了转载递归正则表达式的一般构造方法相关的知识,希望对你有一定的参考价值。

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

作者: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.写出深度1的嵌套表达式

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

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

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

 

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

转载者注,在这个(经我修改的)例子里可以这么写:

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

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

以上是关于转载递归正则表达式的一般构造方法的主要内容,如果未能解决你的问题,请参考以下文章

javascript正则表达式笔记(转载)

js之数据类型(对象类型——构造器对象——正则)

C# 正则表达式

与 boost 正则表达式库的递归匹配

[转载]IOS开发-正则表达式的使用方法

[ 转载 ] 什么是正则表达式的贪婪与非贪婪匹配