`

java 正则表达式 非捕获组(特殊构造)Special Constructs(Non-Capturing)

阅读更多
针对Java API文档中的正则表达式关于特殊构造(非捕获组)的说明,例如:
1.(?:X) X, as a non-capturing group
2.(?idmsux-idmsux)  Nothing, but turns match flags on - off
3.(?idmsux-idmsux:X)   X, as a non-capturing group with the given flags on - off
4.(?=X) X, via zero-width positive lookahead
5.(?!X) X, via zero-width negative lookahead
6.(?<=X) X, via zero-width positive lookbehind
7.(?<!X) X, via zero-width negative lookbehind
8.(?>X) X, as an independent, non-capturing group

1.(?:X) X,作为非捕获组
2.(?idmsux-idmsux) Nothing,但是将匹配标志由 on 转为 off
3.(?idmsux-idmsux:X) X,作为带有给定标志 on - off 的非捕获组
4.(?=X) X,通过零宽度的正 lookahead
5.(?!X) X,通过零宽度的负 lookahead
6.(?<=X) X,通过零宽度的正 lookbehind
7.(?<!X) X,通过零宽度的负 lookbehind
8.(?>X) X,作为独立的非捕获组

现在主要是针对以上8个Regular Expression的Meta Data进行研究:
我们都知道以(?开头,)结尾的都称之为非捕获组,在匹配完成后在内存中不保留匹配到的字符。
1、(?:X) X,作为非捕获组
与捕获组 ( ) 的意思一样也是将其作为一组进行处理,与捕获组的区别在于不捕获匹配的文本,
仅仅作为分组。
比如:要匹配 123123 这个,就可以写为 (123)\1 使用反向引用,这时只能用捕获组,在匹配
123 后会保留在内存中,便于反向引用,而 (?:123) 在匹配完后则不会保留,区别仅在于此。

2、(?idmsux-idmsux) Nothing,但是将匹配标志i d m s u x on - off
用于标志匹配,比如:表达式 (?i)abc(?-i)def 这时,(?i) 打开不区分大小写开关,abc 匹配
不区分大小地进行匹配,(?-i) 关闭标志,恢复不区分大小写,这时的 def 只能匹配 def

3、(?idmsux-idmsux:X) X,作为带有给定标志 i d m s u x on - off
与上面的类似,上面的表达式,可以改写成为:(?i:abc)def,或者 (?i)abc(?-i:def)

4、(?=X) X,通过零宽度的正 lookahead
5、(?!X) X,通过零宽度的负 lookahead
(?=X) 表示当前位置(即字符的缝隙)后面允许出现的字符,比如:表示式 a(?=b),在字符串为
ab 时,可能匹配 a,后面的 (?=b) 表示,a 后面的缝隙,可以看作是零宽度。
(?!X) 表示当前位置后面不允许出现的字符

6、(? <=X) X,通过零宽度的正 lookbehind
7、(? <!X) X,通过零宽度的负 lookbehind
这两个与上面两个类似,上面两个是向后看,这个是向前看

8、(?>X) X,作为独立的非捕获组
匹配成功不进行回溯,这个比较复杂,也侵占量词“+”可以通用,比如:\d++ 可以写为 (?>\d+)。

我认为,第1、2、3点比较好理解,4、5、6、7看类懂,还是用示例来说明:从“aacabab”找a,且后面只允许出现b。代码如下:
Pattern p = Pattern.compile("a(?=b)");
Matcher m = p.matcher("aacabab");
while(m.find()) {
    System.out.println(m.group()+", start="+m.start()+", end="+m.end());
}

运行结果:
a, start=3, end=4
a, start=5, end=6

个人理解:在(?=b)这个“式”后面允许出现b,且这个“式”不占正则表达式位置(所谓0宽度),lookahead 的意思是b字符的前面,它前面紧接着是a,也就是a后面出现b。

8比较难理解, 推荐的链接找到答案:
http://www.regular-expressions.info/atomic.html

其中说的示例:来看 /\b(integer|insert|in)\b/ 匹配 integers 过程,第一个,当integer\b匹配到s时失败,然后字符串(integers)会回溯到i,再接着第二个(insert)去匹配。而把模式写成 /\b(?>integer|insert|in)\b/ 在刚才的第一个匹配失败,字符串(integers)不会回溯了,也不会有第二个去匹配了,所有速度会快一点点。

但是写 (?>X) 这种式子时要注意,是从左到右看的。/\b(?>integer|insert|in)\b/ ,与 /\b(?>in|integer|insert)\b/ 去匹配 insert,结果会不一样,前者可以匹配到,后者不能,什么原因自己分析下。一但匹配失败就会跳过,所以应该长的写在表达式前面。

参考:
http://topic.csdn.net/u/20080503/01/3c82b040-43b9-4b44-847d-07b366285957.html
http://www.regular-expressions.info/atomic.html

java正则表达式的(?:X),(?=X),(?!X),(?<=X),(?<!X),(?>X)的含义

(?:pattern) 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。

(?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如, 'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

(?!pattern) 负向预查,在任何不匹配Negative lookahead matches the search string at any point where a string not matching pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics