Raymond Raymond

浅谈正则表达式匹配嵌套HTML标签

event 2010-06-09 visibility 2,819 comment 0 insights toc
more_vert
insights Stats
浅谈正则表达式匹配嵌套HTML标签

在.NET中我们可以很容易的使用Regex类创建正则表达式对象,用于匹配、替换、筛选数据等,对于文本处理是非常有用的。

由于时间关系,本文不对正则表达式本身作介绍,而仅分析嵌套匹配的正则表达式作简单的分析。

一,匹配单一的嵌套标签

这种情况是比较简单的,因为只是匹配单一的嵌套标签,比如:

<div>我是一层<div>
</div>
<div class="test">
我是二层div
<div class="test">
我是三层div</div></div>
<div class="test">
我是二层div</div>
<div class="test">
我是二层div</div>
</div>

我们可以看出,在上面的HTML片断中只有div标签,那么正则表达式可以写成:

<div[^>]*>[^<>]* #匹配开始div以及非标签内容
(
(
(?'Open'<div[^>]*>)[^<>]*)+ #匹配开始div标签
((?'-Open'</div>)[^<>]*)+    #匹配结束div标签
)*
(?(Open)(?!)#如果堆栈上还有匹配组Open则匹配失败
)
</div> #匹配结尾div

在Regex Tester中测试结果:


如果我们在标签中添加<p></p><ul></ul>等其它标签那么匹配就会失败了,不能匹配最外层的div标签。

二,修改的嵌套div正则,可包含其它标签

将HTML修改为:

<div>我是一层<div>
</div><ul></ul>
<div class="test">
我是二层div
<div class="test">
我是三层div</div></div>
<div class="test">
我是二层div</div>
<div class="test">
我是二层div</div>
</div>

正则表达式修改为:

<div[^>]*> #开始div标签
(?<tagcontent> #将div标签之间的所有内容捕获到组tagcontent中
(.|\n)*? #匹配任意字符或者换行符但是尽量少
(
(
(?'Open'<div[^>]*>) #匹配嵌套的div开始标签
(.|\n)*? #匹配开始div标签后的内容
)+ #匹配至少一个div开始标签,开始标签后面可以不跟任何内容也可以包含其它标签
(
(?'-Open'</div>) #匹配嵌套的div闭合标签
(.|\n)*? #匹配闭合div标签后的内容
)+ #匹配至少一个div闭合标签,闭合标签后面可以不跟任何内容也可以包含其它标签
)* #开始标签和闭合标签匹配0次或者以上的情况
(?(Open)(?!))#如果堆栈上还有组名为Open的项则匹配失败
)
</div> #结束div标签

在Regex Tester中测试结果为:


三,其它的相关说明

在二中,如果我们在html中多添加一个<div>标签或者在结束前添加一个</div>标签,那么整个html不是valid的xhtml,比如:

<div>我是一层<div><div>
</div><ul></ul>
<div class="test">
我是二层div
<div class="test">
我是三层div</div></div>
<div class="test">
我是二层div</div>
<div class="test">
我是二层div</div>
</div>

在上述中,如果将正则中(?(Open)(?!))注释掉,那么会多一个匹配组Open,且其内容为<div>,如果不注释那么匹配组Open的内容就会是一个位置而已,其Index为0,Length为0。

如果HTML为:

<div>我是一层<div>
</div><ul></ul>
<div class="test">
我是二层div
<div class="test">
我是三层div</div></div>
<div class="test">
我是二层div</div>
<div class="test">
我是二层div</div></div>
</div>

那么最后一个多余的</div>不会匹配上。

有一点在参考文章中也有提到,这里再次强调下:

其中(?<-N>)是表示释放之前捕获的N分组。确切的语法是(?<N-M>)即使用N分组替换掉M分组,如果N分组没有指定或不存在,则释放M分组。

参考文档

使用正则表达式匹配嵌套Html标签

正则表达式30分钟入门教程

More from Kontext
comment Comments
No comments yet.

Please log in or register to comment.

account_circle Log in person_add Register

Log in with external accounts