正则群里逍遥(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);
浙公网安备 33010602011771号