另外要说明一点,在.NET等使用Unicode的语言和javascript等使用ASCII码的语言中,/b的意义虽然可以采用同样的解释,但是匹配的结果是不一样的
源字符串:a中文
正则表达式:a/b
在.NET中是匹配失败的,而在javascript中是匹配成功的
.NET中,只有加了RegexOptions.ECMAScript参数,/b的意义才与javascript中一样
首先,这个正则只在极特殊的情况下才有意义,绝大多数情况下,它的意义只存在于理论上,如果换成((? <=/d)/d{3})+/b,才会有些实际意义
其次,我不知道楼主是在哪里调试的,用的什么样的调试代码,执行结果怎么可能是楼主给出的结果
-
C# code
-
string [] test = new string [] { " 789456123 " , " 1234567890 " , " -123456 " }; foreach ( string s in test) { richTextBox2.Text += " 源字符串: " + s + " /n " ; MatchCollection mc = Regex.Matches(s, @" ((?<=/d)/d{3})*/b " ); foreach (Match m in mc) { richTextBox2.Text += " 匹配结果: " + m.Value + " ,Index: " + m.Index + " ,Length: " + m.Length + " /n " ; } richTextBox2.Text += " /n " ; } // 输出 源字符串: 789456123 匹配结果:,Index: 0 ,Length: 0 匹配结果: 456123 ,Index: 3 ,Length: 6 匹配结果:,Index: 9 ,Length: 0 源字符串: 1234567890 匹配结果:,Index: 0 ,Length: 0 匹配结果: 234567890 ,Index: 1 ,Length: 9 匹配结果:,Index: 10 ,Length: 0 源字符串: - 123456 匹配结果:,Index: 1 ,Length: 0 匹配结果: 456 ,Index: 4 ,Length: 3 匹配结果:,Index: 7 ,Length: 0
之所以说楼主这个正则只有在极特殊情况下才有意义,是因为整个表达式可以匹配零宽度的字符串,所以在源字符串是任何形式的情况下,都会有匹配成功的结果,通常来说,这是没有意义的
最后,来分析一下这个正则的匹配原理
这个问题跟我前几天回答的另一个帖子,有很多相似之处,可以先参考一下这个帖子10楼主的归纳方法, 正则表达式正向预搜索的问题
楼主的表达式,也可以进行归纳,最终就可以归纳为
-
C# code
-
(( ? <= /d)(/d{ 3 }) * ) ? /b
当然,这个表达式似乎也不是那么容易理解,所以还是按原来的表达式分析吧
之所以不能写成(? <=/d)(/d{3})*/b,是因为(? <=/d)并不是必须的,只有后面出现/d{3}时,它才是必须的
我只分析一个源字符串是789456123的情况,其它源字符串原理一样
源字符串:789456123
正则表达式:((? <=/d)/d{3})*/b
首先对源字符串进行一下说明,字符“7”之前,是字符串的起始位置,记作位置0,字符“7”和字符“8”之间记作位置1,以此类推
首先从位置0开始尝试匹配,正则引擎把控制权交给((? <=/d)/d{3})*,可以把它看作(Exp)*,因为是贪婪模式,正则引擎会先尝试用Exp来进行匹配,此时控制权交给(? <=/d),在位置0处,它的左侧没有任何字符,当然也就不会是数字,所以在位置0处,(? <=/d)匹配失败,(? <=/d)/d{3}也就匹配失败,回溯,((? <=/d)/d{3})*不进行匹配,此时控制权交给/b,位置0左侧和右侧满足/b条件,/b在位置0匹配成功,整个表达式在位置0处就匹配成功,因些会返回匹配结果,匹配内容为空字符串,Index为0,长度当然就是0
继续尝试下一次匹配,此时正则引擎会引导正则向前传动,从上一次匹配成功的结束位置开始尝试匹配,如果匹配成功的开始和结束位置相同,则从下一个位置开始尝试匹配
接下来也就是在位置1尝试匹配,正则引擎把控制权交给((? <=/d)/d{3})*,因为位置1的左侧是字符“7”,满足要求,向右匹配三个数字,先是“8”,接着“9”,接着“4”,匹配成功,这时((? <=/d)/d{3})*会接着上次匹配成功的位置,尝试第二次匹配,同样成功的匹配了“561”,接着尝试第三次匹配,首先匹配成功了“2”,接着匹配成功了“3”,再向右匹配,因为不是数字,匹配失败,((? <=/d)/d{3})*回溯,((? <=/d)/d{3})成功匹配了两次,也就是匹配成功了“894561”,正则引擎把控制权交给/b,在“1”后面,“2”前面这个位置尝试匹配,当然匹配失败,((? <=/d)/d{3})*再回溯,匹配成功一次,也就是匹配成功了“894”,正则引擎把控制权交给/b,在“4”后面,“5”前面这个位置尝试匹配,当然匹配失败,((? <=/d)/d{3})*再回溯,匹配成功零次,也就是不匹配,正则引擎把控制权交给/b,在“7”后面,“8”前面这个位置尝试匹配,当然匹配失败,((? <=/d)/d{3})*已经无法再回溯,此时整个表达式匹配失败
继续尝试下一次匹配,此时正则引擎会引导正则向前传动,从下一个位置开始尝试匹配,也就是在位置2尝试匹配,过程同上,同样匹配失败
继续尝试下一次匹配,此时正则引擎会引导正则向前传动,从下一个位置开始尝试匹配,也就是在位置3尝试匹配,过程同上,((? <=/d)/d{3})*成功匹配两次,此时在结束位置,/b也匹配成功,因此整个表达式匹配成功,匹配内容为“456123”,Index为3,长度为6
继续尝试下一次匹配,此时正则引擎会引导正则向前传动,从下一个位置开始尝试匹配,也就是在结束位置尝试匹配,过程同上,((? <=/d)/d{3})*匹配零次,/b匹配成功,整个表达式匹配成功,匹配内容为空字符串,Index为9,长度当然就是0