.NET中对无限层匹配嵌套结构的正则匹配

分享.NET正则表达式 by 达达 at 2008-03-03

在开发模板引擎时遇到了一个用正则表达式比较难以处理的情况,就是无限级的嵌套结构的匹配。HTML标签就属于这种结构。

举个具体的例子,下面是我们要匹配的内容:

<x>
    <x></x>
    <y></y>
</x>
<x></x>

在找到用正则匹配无限层嵌套结构的方法之前,我只能绕弯路来实现对无限层嵌套结构的匹配。

我只能用正则先把每个独立的标签匹配出来,然后用第一个标签名x做参数,逐一的查找匹配出来的每一个独立标签,看看他是否是第一个x对应的闭合标签。

这种方式得加上判断嵌套层次的代码,还得匹配和循环很多没有用的数据。

后来我才了解到.NET提供了一个正则表达式的扩展特性,用来帮助处理无限层嵌套结构的匹配。这种特性是.NET特有的,别的编程语言或者平台不一定会有。

我们都知道正则的匹配组的概念,它的语法是 (?<组名>)。使用这个正则语法我们可以建立一个匹配组。其实这是一个入栈的过程。

而.NET对正则的匹配组做了一个特殊的支持 (?<-组名>)。使用这个正则语法我们可以将指定组名的最后匹配结果去除。也就是出栈了。

一个入栈一个出栈,这一入一出就为我们提供了匹配无限层嵌套的可能 :)

下面举个例子看看怎么实现无限层嵌套的匹配:

regex-test2.png

从图中我们可以看出正则正确的匹配出了最顶层的三个<x></x>结构,而嵌套在第二个<x></x>结构中的标签被当成了结构的内容。这是怎么做到的呢?

下面是图中的正则,我加入了注释:

<x>
(?>
  <x>(?<n>)          #在匹配到<x>时,将匹配组n入栈
  |
  </x>(?<-n>)        #在匹配到</x>时,将匹配组n出栈
  |
  (?!<x>|</x>).      #匹配除<x>和</x>以外的其他字符
)*
(?(n)(?!))           #如果执行到此处还存在匹配组n,则匹配失败,重新匹配
</x>

这段正则中还用到了平时比较少使用到的(?!(name)yes|no)语法,这个语法相当于C语言的if语法,用于做条件判断,之用。上面的正则中我们用它来片段是否存在命名组n,如果存在命名组n,说明标记没有对称闭合,用(?!)断言匹配失败,重新匹配。

在《Mastering Regular Expressions》中似乎有相关章节提到这种无限层嵌套结构的匹配,不过我手头没这本书。我是从这里学习到这种特殊的正则语法的,大家可以参考下 :)