预搜索经典案例分析
2012-03-31 14:06 Andy Ge 阅读(289) 评论(0) 编辑 收藏 举报
string str ="aaa bbbb ffffff 999999999"; Regex r = new Regex(@"(\w)((?=\1\1\1)(\1))+"); foreach (Match m in r.Matches(str)) { Console.WriteLine("Match:Value={0},Index={1},Length={2}", m.Value, m.Index, m.Length); }
结果如下:
Match:Value=bb,Index=4,Length=2
Match:Value=ffff,Index=9,Length=4
Match:Value=9999999,Index=16,Length=7
表达式 "(\w)((?=\1\1\1)(\1))+" 在匹配字符串 "aaa ffffff 999999999" 时,将可以匹配4个"b"的前2个,可以匹配6个"f"的前4个,可以匹配9个"9"的前7个。我想问的是为什么漏掉的总是最后两个字母?它们为什么不能匹配成功?哪个规则导致了这种影响?能详细说说好吗?
(\w) # 匹配一个单词字符
( # 分组开始
(?=\1\1\1) # 紧接着必须是三个和前面的一样的字符,但不吃进字符
(\1) # 匹配一个和前面一样的字符
)+# 匹配一个或多个这样的分组
楼主的正则,(\w)((?=\1\1\1)(\1))+,其实就等价于
(\w)(\1)*(?=\1\1\1)(\1)
这个会相对好理解一些
说下分析过程,因为+表示{1,},下面的“次数”表示((?=\1\1\1)(\1))+匹配成功的次数
次数 楼主的正则等价于
1 (\w)((?=\1\1\1)(\1))
2 (\w)((?=\1\1\1)(\1))((?=\1\1\1)(\1))
3 (\w)((?=\1\1\1)(\1))((?=\1\1\1)(\1))((?=\1\1\1)(\1))
...
因为如果最后一个((?=\1\1\1)(\1))匹配成功,那么中间的((?=\1\1\1)(\1))一定成功,所以中间的限制条件(?=\1\1\1)就没有意义了,这时就可以简写为(\1)
也就是
次数 楼主的正则等价于
1 (\w)((?=\1\1\1)(\1))
2 (\w)(\1)((?=\1\1\1)(\1))
3 (\w)(\1)(\1)((?=\1\1\1)(\1))
...
可以归纳为等价于
(\w)(\1)*((?=\1\1\1)(\1))
因为((?=\1\1\1)(\1))开始和结尾的()原来是用作量词+限制范围的,这里已经没有什么意义了,所以表达式最后可以归纳为等价于
(\w)(\1)*(?=\1\1\1)(\1)
分析这个表达式就容易多了
(\w)匹配一个字符,占一位,\1是对\w匹配内容的引用,(\1)*可以匹配0到无穷多个(\w)匹配到的字符,(?=\1\1\1)(\1)只占一位,但是(?=\1\1\1)要求所在位置右侧有三个(\w)匹配到的字符,所以在(?=\1\1\1)这个位置右侧应该有三个字符,只是最后两个不计入最后的匹配结果
以999999999为例,第一个9由(\w)匹配,第二到第六个9由(\1)来匹配,第七个9由(?=\1\1\1)(\1)中最后的(\1)来匹配,而第七、八、九这三个9是用来保证满足(?=\1\1\1)这个条件的