(轉)使用零寬斷言來匹配不包含連續字符串的行

原文地址:http://blog.khotyn.com/blog/2013/07/24/zero-width-assert/java

最近在工做中遇到一個問題,有 N 個字符串,須要用正則表達式去過濾掉不包含某一個特定連續字符串(好比abc)的字符串。正則表達式

在網上搜羅了一大把,找到了在 Perl 5 的正則表達式中有零寬斷言這個東西,很是強大,先來了解下零寬斷言卻是是什麼?服務器

簡單的說,零寬斷言是查找在某些內容以前或者以後的東西,這樣解釋起來可能比較抽象,咱們來具體看下幾種零寬斷言:app

  • (?=exp):這個零寬斷言用來斷言自身出現的位置以後可以匹配到表達式 exp,考慮下面這一個正則表達式 q(?=u),這個正則表達式表示匹配後面的字符是 u 的 q
  • (?!exp):這個零寬斷言用來斷言自身出現的位置以後不可以匹配到表達式 exp,看下面這一個正則表達式 q(?!u),這個正則表達式表示匹配後面的字符不是 u 的 q
  • (?<=exp):這個零寬斷言用來斷言自身出現的位置以前可以匹配到表達式 exp
  • (?<!exp):這個零寬斷言用來斷言自身出現的位置以前不可以匹配到表達式 exp

在理解零寬斷言的時候須要注意的一點是它是一種斷言,也就是說零寬斷言只會告訴你匹不匹配,可是不會「消費」掉字符串內的內容,我用下面的這一個例子來解釋這個狀況: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 上還有一份,因而就遷移過來。這幾年我常常用這個方式來分析線上服務器的日誌,能夠說,有了零寬斷言,省去了很是多的麻煩~,定位問題的速度也快了很多,零寬斷言的確是一個很是犀利的東西。

相關文章
相關標籤/搜索