.net正则表达式逆序环视中反向引用来看匹配过程。

正则群里逍遥(blog.csdn.net/wuyazhe)发了一个帖子链接,是关于在正则表达式的逆序环视中应用反向引用出现的问题。楼主的问题比较经典,而楼下TIM引用过客的帖子也是非常好的,我多次在不同场合推荐过客的博客也从这篇博客中看出原因来。但是可惜的是明显Tim没有看问题,给出的链接也必然不是楼主提出问题的解决。因此逍遥在下面进行了相应的分析和猜想。可惜的是逍遥的分析也没有找到point所在,因此才有了楼主的第二个帖子


之所有说了这么多的废话,是希望看到这篇博客的童鞋能认真看完帖子,并能够知道逍遥、tim、过客等正则达人,从他们的博客中多多少少能学到一些知识,同时也是让您能够了解问题所在和一个对问题的认识。我在第一个帖子回复了答案之后草草的离开了,一方面是因为当时确实有点忙,更主要的原因是我不善言辞,更不善总结,故不敢乱言(我在js版块里经常会因为失言而误导提问者,因此之后我也很少写原理性的东西,多以代码来解释)。不过后来兔子党理事童鞋也对此产生不解,我就顺便写了一组demo来说明下,没有深入的分析,但是在注释中也解释了问题的所在。反向引用是指一个匹配了的分组在正则后面引用匹配的分组结果,多数用在查重和呼应(比如引号,标签等)。在很多时候我们的反向引用也如其名会在表达式的前面写分组,表达式后面写引用,比如(.)\1这样的文本顺序,但是逆序环视下环视内表达式是从右向左搜索的。因此这个分组和这个反向引用的引用顺序要相反而出。但是在实验过程中得到的结论并非是一点问题没有的。在这里我们先看这些demo

            string str = "abcde";
            Regex reg = new Regex(@"(?<=(.)(.))(.)(?=(.)(.))");
            Match match = reg.Match(str);
            for (int i = 1; i < match.Groups.Count; i++)  //groups0是指匹配本身的value
            {
                Console.WriteLine(match.Groups[i].Value);
                /*
                 * 和你预测的一样。从左到右的得到结果
                 * output: 
                 * a 
                 * b
                 * c
                 * d
                 * e
                 */
            }

            string str1 = "11111";
            Regex reg1 = new Regex(@"(?<=\1(.))\1(?=\1\1)");
            Console.WriteLine(reg1.IsMatch(str1));
            /*
             * 是不是有点意外。这个结果。。。
             * output:
             * True
             */

            string str2 = "11111";
            Regex reg2 = new Regex(@"\d+", RegexOptions.RightToLeft);
            Console.WriteLine(reg2.Match(str2));
            /*
             * 给出了最大匹配即11111
             */

            //猜测1,逆序环视难道是RightToLeft?
            string str3 = "12345";
            Regex reg3 = new Regex(@"(?<=(?<name>.)+)$");
            foreach (Capture c in reg3.Match(str3).Groups["name"].Captures)
            {
                Console.WriteLine(c.Value);
            }
            /*
             * 这一步中我得不到任何的结论,只能说明在逆序环视中,他确实是从右往左逐个匹配量词。但是不能证明他怎么匹配环视中的表达式。因此测试要继续
             * output:
             * 5
             * 4
             * 3
             * 2
             * 1
             */

            string str4 = "12345";
            Regex reg4 = new Regex(@"(?<=(?<first>\d+)(?<second>\d+))$");
            Match m4 = reg4.Match(str4);
            Console.WriteLine(m4.Groups["first"]);
            Console.WriteLine(m4.Groups["second"]);
            /*
             * 这个例子中,如果假设是从first分组开始匹配的话 那么应该得到的结果是1234 和5
             * output:
             * 1
             * 2345
             * 
             * 我们可以初步的判定,他确实RightToLeft的可能性高些,最后我们再来做个实验
             */


            string str5 = "12345";
            Regex reg5 = new Regex(@"^(?=(?<first>\d+)(?<second>\d+))");
            Match m5 = reg5.Match(str5);
            Console.WriteLine(m5.Groups["first"]);
            Console.WriteLine(m5.Groups["second"]);
            /*
             * 在顺序环视中,和我们想象的一样,得到是1234和5
             * output:
             * 1234
             * 5
             */

            /*
             * 我不能确定这是不是.net特有的,因为逆序环视中带不定量词还只有.net有。所以这种情况也往往只有在.net才用上。
             * 我不是在下定义,也不是在做总结,以上实验仅限个人理解。如果有过客等大牛的科普,请忽视以上。
             */

接下来,让我们来看看我说的问题

            string str = "111";
            Regex reg = new Regex(@".+(?<=(\d)\1(\d))$");
            Match mc = reg.Match(str);
            Console.WriteLine(mc);
            /*
             * 惊奇吧,什么都没匹配到,如果如上所说,那么起码这个demo应该可以匹配到。无论从哪个方向这也是匹配的
             * 然而可惜的是,他竟然什么都匹配不到,那这到底是为什么呢。
             * output:
             * 
             */

            string str2 = "123";
            Regex reg2 = new Regex(@"(?<=(\d)(\d)(\d))$");
            Match m2 = reg2.Match(str2);
            for (int i = 0; i < m2.Groups.Count; i++)
            {
                Console.WriteLine(m2.Groups[i]);
            }
            /*
             * 由之前的一组匹配得到的结论是匹配从右往左,而这个例子又说明,分组的顺序又是从表达式文本的从左往右计数
             * 那么如果命名这些分组呢?
             * output:
             * 1
             * 2
             * 3
             */

            string str3 = "111";
            Regex reg3 = new Regex(@"(?<=(?<first>\d)\<second>(?<second>\d))$");
            Regex reg31 = new Regex(@"(?<=(?<first>\d)\<first>(?<second>\d))$");
            Match m3 = reg3.Match(str3);
            Match m31 = reg31.Match(str3);
            Console.WriteLine(m3.Success);
            Console.WriteLine(m31.Success);
            /*
             * 命名后的话,我们可以得到如第一组demo的结论
             * output:
             * True
             * False
             */

到此为止我没有得到一个合理的结论,虽然逆序环视从右往左探索是msdn的官方说明,但是这个问题又如何解释呢,期待牛人解答。也许什么时候我能想到一个合理的解释也会更新此博客


感谢逍遥的提醒,如果按照这个说法:"编组是按照从左到右(表达式)进行编组的,而逆序环视匹配是从右往左"那么就可以说通了。比如下面的demo.

            string str = "111";
            Regex reg = new Regex(@".+(?<=(\d)\2(\d))$");
            Match mc = reg.Match(str);
            Console.WriteLine(mc); 

在这里,我要说一下,CSDN的博客代码高亮还是有问题,我的$"符号就变成了{1}quot;

算不算提交了BUG,给个奖励呗。。。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值