原文地址:http://blog.khotyn.com/blog/2013/07/24/zero-width-assert/java
最近在工做中遇到一个问题,有 N 个字符串,须要用正则表达式去过滤掉不包含某一个特定连续字符串(好比abc)的字符串。正则表达式
在网上搜罗了一大把,找到了在 Perl 5 的正则表达式中有零宽断言这个东西,很是强大,先来了解下零宽断言却是是什么?服务器
简单的说,零宽断言是查找在某些内容以前或者以后的东西,这样解释起来可能比较抽象,咱们来具体看下几种零宽断言:app
在理解零宽断言的时候须要注意的一点是它是一种断言,也就是说零宽断言只会告诉你匹不匹配,可是不会“消费”掉字符串内的内容,我用下面的这一个例子来解释这个状况:spa
咱们有一个正则表达式 k(?=h)otyn
,用它去匹配 khotyn,乍看一下这个匹配是会成功的,可是因为零宽断言只作断言,而不会”消费“掉匹配到的字符串,因此事实上,这个正则表达式匹配是一个后面是 h 的 k,而且这个 k 的后面是 otyn,这样这个正则表达式不管什么字符串都会匹配失败(正确的应该是 k(?=h)hotyn
,不过这样加不加零宽断言并无意义)。日志
在理解零宽断言之后,咱们来看一下如何来匹配出不包含“abc”的字符串,下面是我写出的结果:code
1
|
((?!abc).)+ |
首先咱们看这个正则表达式里面的 (?!abc).
部分,这个部分断言一个空字符后面不可以匹配到字符串abc,而且这个空字符串后面是一个任意字符。blog
咱们来看下下面这一段代码:字符串
1 2 3 4 |
Pattern pattern = new Perl5Compiler().compile("((?!abc).)+"); Perl5Matcher matcher = new Perl5Matcher(); System.out.println(matcher.matches("abc", pattern)); System.out.println(matcher.matches("abdas dfas", pattern)); |
这段代码的执行结果是:get
1 2 |
false true |
第一个匹配失败是由于在字符 ‘a’ 前面的空字符后面匹配到了字符串 “abc”,所以断言失败,从而匹配失败。
第二个匹配成功是由于没有任何一个空字符后面有出现 “abc” ,由于匹配成功。
最后加上 + 号的缘由是由于可以作到彻底匹配,由于任何一个字符只要其自己不是 ‘a’,而且后面不是 ‘bc’,那么就是可以匹配 “(?!abc).” 的,所以,只要一个字符串里面不包含 abc,那么它就可以彻底匹配 ((?abc).)+
PS:这片文章实际上是前几年写的,以前的博客被关闭了,数据丢了,幸亏当时在 Iteye 上还有一份,因而就迁移过来。这几年我常常用这个方式来分析线上服务器的日志,能够说,有了零宽断言,省去了很是多的麻烦~,定位问题的速度也快了很多,零宽断言的确是一个很是犀利的东西。