正则群里逍遥(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,给个奖励呗。。。