C#正则表达式(4):平衡组,递归匹配

来源:互联网 发布:js focus有什么 编辑:程序博客网 时间:2024/06/05 17:26

看到平衡组,递归匹配这样的太充满术语性的名词又要头大了啊.其实简单点讲就是怎么去匹配那些互相匹配并且互相嵌套的字符对.

比如(),[],{}这样的配对的括号.如果你写代码时某个函数很长很长,那些嵌套的{}会把你搞晕了,不知道哪个配哪个了啊.那编译时人家编译器怎么知道呢.它就是通过类似平衡组的理论去识别.还有html,xml里面会有一堆<>这样的尖括号,如果不知道怎么去匹配配对的<>那肯定就乱套了.这里同样也用到平衡组类似的理论

先来讲点C#栈(Stack)的知识

那怎么才能去正确的匹配呢.很多大学课程里学数据结构这门课时可能会有这样的一个习题,就是有一个字符串里面有数字和算术操作符和括号.怎么把它解析出来当成算术表达式并得到结果.比如string str = "(3+4)*(9-5) - 2";怎么把它解析出来并算出结果.要实现这样的目的最简单的思路就是用栈这种数据结构.它是后进后出的一种结构.往栈中加入元素叫入栈,

从栈中删除元素叫出栈.假如传入字符'('则入栈,传入字符')'时不仅不入栈,还把之前的'('给删除掉.用C#的代码可以这样写

char input = '(';

Stack<char> stack = new Stack<char>();

            if (input == '(')

                stack.Push(input);

            if (input == ')')

                stack.Pop();

        if (stack.Count == 0)       //判断栈里面的元素是否为空

                return true;

          else

               return false;

你可能奇怪在这里为啥讲这么跟正则表达式无关的东东.其实不是无关,而是很相关.你用平衡组,递归匹配能实现的功能,也同样能通过上面说的这种Stack来写代码来实现.只不过比较复杂一点.比如要加上些循环判断.而正则表达式里也肯定同样用到了栈,只不过封装了,你看不到.

平衡组,递归匹配

正则表达式里是这样用到栈的

(?'group'exp)    这其实就是前面讲的给一个分组命名,exp是一个字符串,用括号括起来就成一个分组了,group就是组名.只是它除了起命名的作用外,后台的操作就是把exp入栈

                        假如exp是左括号即(?'group'\(),则它的操作实际上和前面的代码if (input == '(')    stack.Push(input); 一样

(?'-group'exp)   这里多了个-表示出栈.假如exp是右括号)即(?'-group'\))则它的操作和前面的代码if (input == ')')   stack.Pop();一样.把exp出栈

(?(group)yes|no) 如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分.其实这里yes和no可以去年一个

往往是去掉yes,就留下no而no也基本上不做其他操作,只是返回个表示匹配成功或失败的标志.这里用(?!)来表示匹配失败.前面有讲过零宽断言.它就是一种特殊的断言.

所以我们大部分时候的是这样用

(?(group)(?!) 它的意思和上面的代码一样.if (stack.Count == 0)       //判断栈里面的元素为空

                return true;

          else

               return false;

在这里举个比较简单的例子.要假如有一字符串.要匹配其中以第一个左尖括号后面开始出现的尖括号对<>里的内容

string source = "**<a<b<arwen>c>other>**";

string pattern = @"[^<>]*  #匹配任何非尖括号的字符

                        (?'group'<)    #匹配<并且入栈

                         [^<>]*        #匹配任意非尖括号的字符

                        (?'-group'>)   #匹配>并且出栈

                        [^<>]*         #匹配任意非尖括号的字符

                      (?(group)(?!))   #判断栈中是否为空,为空则匹配成功,否则失败

                          ";

Console.WriteLine(Regex.Match(source, pattern,RegexOptions.IgnorePatternWhitespace).Value);

 

结果是

b<arwen>c