淺析正則表達式——柳暗花明又一村篇


一、前言

  本文章主要針對上篇文章進行補充,接上一篇文章http://www.cnblogs.com/dwlsxj/p/3532458.html,首先為什么開篇叫柳暗花明又一村,大家都知道這個詞的解釋:一個人在想某個問題或做某件事的時候,遇到了一定阻礙,但是后來某個時刻突然來了靈感,使問題得到解決!就是那種“頓悟”的意思!由於前面一篇文章中有人說看到零寬度和占有符的時候就看不下去了,看着就有點模糊,那么下面我就針對零寬度進行講解下。零寬度其實就是匹配一個位置,前面我們講了字符串的組成,比如”123”這個字符串有三個字符,四個位置。那么零寬度僅僅是匹配這四個位置,而不占有字符,它不會將內容保存到最后的結果,零寬度的子表達式之間是不互斥的,所以一個位置可以由多個零寬度進行匹配。通篇以例子的形式進行分析講解!

二、柳暗花明又一村

  下面我們借助例子來講述下為什么說零寬度是僅僅匹配一個位置?

  首先我們看一下這個例子:

  我們要寫一個正則表達式,我們要匹配的內容是匹配當前位置后面是SmallDing的,也就是開始位置為SmallDing的正則表達式。我們很容易就聯想到我所說的第二個例子,看看你們中槍沒有?

  例子一:正則表達式為:(?=SmallDing)SmallDing\d+

  源文本:SmallDing520

  首先先看一下結果:

  正則表達式所匹配內容:這個正則表達式的意思是匹配當前匹配的位置后面跟的是SmallDing,后面再進行匹配SmallDing加一串數字。有人會問什么是當前匹配的位置,接下來我們就進行深一層的分析。分析圖詳見下圖:

  我們來分析一下匹配的過程,首先得到控制權的是(?=SmallDing),從位置0處進行匹配,由於該表達式是零寬度,僅僅是匹配一個位置,並不將內容保存到最后結果,環視位置0處后面跟的是不是SmallDing(位置0處就相當於是當前匹配的位置),可以理解為從位置0處向右環視是不是SmallDing,如果是匹配成功,如果不是就匹配失敗,這里我們匹配成功,接下來我們將控制權傳動給正則表達式中的“S”,前面我們已經說過了零寬度僅僅是匹配一個位置,它的從位置0開始也是從位置0結束,那么正則表達式中的S就會還是從位置0處進行匹配,匹配源文本中的S,匹配成功,控制權向右傳動,以此類推,直到匹配結束。 

  例子二:

  正則表達式:(?=SmallDing)\d+

  源文本:SmallDing520

  匹配結果:空

  詳情請見下圖所示:

  

  我們現在就來進行對其進行分析,整個正則表達式的含義是匹配當前位置后面跟的是SmallDing,但是不匹配SmallDing,后面還有數字重復1次以上。

  接下來我們就進行分析這正則表達式匹配的情況,首先源文本的結構圖見下圖所示:

  首先這里就有一個誤區,我們大家初學的時候都以為零寬度斷言是雖然不匹配文本,但是感覺位置是進行改變的,也就是匹配零寬度子表達式匹配的位置會移動到位置9處,其實不是這樣接下來我們就來分析下。

  正則表達式從左往右依次匹配,首先得到控制權的是正則表達式中的(?=SmallDing),它會從位置0處進行匹配,僅僅匹配一個位置,不會將內容保存到最后的結果中,從位置0處向右環視該零寬度子表達式SmallDing與源文本的SmallDing進行匹配,符合要求,匹配成功。控制權傳動給正則表達式的”\d+”,由於零寬度我們講過只匹配一個位置,它從位置0開始也是從位置0結束,所以”\d+”從位置0處進行匹配,匹配源文本的S,匹配失敗,由於正則表達式是向前推動的,所有又從位置1處開始匹配,控制權交給(?=SmallDing),向右進行環視,不符合要求,匹配失敗,正則表達式又向前推動,以此類推直到整個推動結束匹配失敗!

       總結:看似兩個正則表達式沒有什么聯系,而且兩個正則的含義也不一樣,卻能表現出我們剛學正則表達式時的狀況,我們剛開始學正則表達式的時候一直都以為第二個例子是我們想要得到的效果,對呀匹配當前位置后面跟的是SmallDing,不匹配該內容,那么匹配完了后面就應該匹配”\d+”,也就是匹配520,但是通過這篇文章的理解,這種想法是錯的,我們以為是零寬度是占有字符的,它匹配的位置會隨之改變,而不是原地不動。事實上,零寬度斷言是只匹配了位置,而沒有將內容保存到最后的結果當中,因此它開始匹配的位置和結束的位置是不變的。

  看了上面的例子,也許我們會有些聯想,我上篇文章中所說的,(?=exp)另一層理解含義是匹配exp表達式前面的內容。沒錯,是這樣的,(?=exp)在本文所說的是換一個角度講的,換做是匹配位置講的,舉個例子進行說明:看下面的例子

  例子三:

  正則表達式:\b\w+(?=ing\b)

  源文本:doing

  匹配結果:do

  詳情請見下圖:

  解析:正則表達式表示匹配一個單詞開始位置,”\b”它只匹配一個位置,所以它是零寬度的,匹配一個單詞,匹配ing前面的內容。

  下面對匹配過程進行分析,首先先看下面這張圖:

 

 

  匹配過程分析:首先得到控制權的是”\b”,它從位置0處進行匹配,匹配一個位置匹配成功,將控制權轉交給”\w+”,”+”是優先詞量,在可匹配與不匹配的情況下優先嘗試匹配,它從位置0處開始匹配,匹配”D”,符合要求,匹配成功,將其保持到最后結果(也叫吞入一個字符),接下來匹配”o”,符合要求,匹配成功,吞入一個字符,重復上面,匹配到”g”,符合要求,匹配成功,再向后匹配時發現已經到了結尾了,”\w+”這時匹配完成,將控制權   傳動給(?=ing\b),由它來匹配最后位置5處,發現已經到了正則的結束位置,看有沒有可供回溯的狀態,它將控制權轉交給”\w+”,”\w+”讓出三個字符,又將控制權轉交給最后的(?=ing\b),從位置2處開始匹配后面跟的是ing還有一個結束位置,匹配成功,整個表達式匹配完成。

  (?<=exp)

  例子一:

  正則表達式:(?<=SmallDing)\d+

  源文本:SmallDing520

  匹配結果:520

  詳細情況如下圖所示:  

 

  匹配過程:正則表達式從最右側開始進行匹配,首先得到控制權的是(?<=SmallDing),由它從位置0處進行匹配,從位置0處進行環視左邊是不是SmallDing,環視左面不是SmallDing,是開始位置,匹配失敗,由於正則是向前推動的,所以控制權在手的(?<=SmallDing)又開始在位置1處進行匹配,環視左側是S,和零寬度子表達式不相符,匹配失敗,再向前推動,以此類推,一直到位置9處,環視左側是SmallDing與零寬度子表達式相符,匹配成功,由於是零寬度,只匹配位置,並不將內容保存到最后結果中。將控制權傳動給正則表達式的”\d+”,由於“+”是有限詞量,在可匹配的情況下優先嘗試匹配,從位置9處嘗試匹配源文本的5,符合要求,匹配成功,將內容保存到最后結果中,依次匹配直到匹配結束。

  至於還有兩個負零寬度斷言(?!exp)和(?<!exp)基本原理是一樣的,這里就不做詳細講解了,只是跟我們分析的是環視內容相符的,負零寬度斷言是環視內容不相符的。這里補充說明零寬度不僅僅只有這四個,還有^$表示字符串的開始與結束也是匹配一個位置,還有\b匹配單詞的開始與結束的位置,都不占有字符。通過這篇文章我們可以深入理解零寬度和占有符的區別。

三、結束語

  通過這篇文章分析可以使我們理解零寬度和占有符的區別,也希望大家能夠從中找到缺點,小丁將其改正,如果有分析不正確的望指正。

  這里要感謝@宵的天使在上一篇文章提供詳細的正則表達式,讓我有了更好的理解。

  參考文章:http://blog.csdn.net/lxcnn/

  方便大家閱讀,已將文檔傳到網盤網盤地址如下:

  百度網盤鏈接:http://pan.baidu.com/s/1kTKB3Zx 提取密碼:l6q4

  接下來就是對着正則表達式應用的練習:

       淺析正則表達式-應用篇


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM