原文地址: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 上還有一份,因而就遷移過來。這幾年我常常用這個方式來分析線上服務器的日誌,能夠說,有了零寬斷言,省去了很是多的麻煩~,定位問題的速度也快了很多,零寬斷言的確是一個很是犀利的東西。