淺析正則表達式-應用篇


一、前言

  時間匆匆流去,我已經來博客園快要兩年了,在這里我學會了很多知識,博客園給我帶來了知識上的充實和分享的快樂!我現在要分享的是關於正則表達式的一些使用方法,在次聲明:必須有一定的正則表達式的基礎,否則會有些吃力,如果你對基礎不是很了解請翻到這章節:

  淺析正則表達式-原理篇
http://www.cnblogs.com/dwlsxj/p/Regex.html

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

http://www.cnblogs.com/dwlsxj/p/Reg.html

  通過上面兩篇文章的講解我相信正則會有一定的基礎,並會有一定的提升,我們接下來我們就要講解本章的重點內容了,正則表達式的使用,這里很多人都會迷茫,我那些元字符之類的我都背的很熟悉,但是就是寫不好正則表達式,不知道從哪里下手,我相信通過這篇文章會給大家帶來一個思路,我這里說的只是小弟的一些心得,以及這么長時間來對正則使用的一些感悟。

二、應用篇

       我們這里不會說太多理論方面的知識,這樣看的也有些厭煩,我從實例出發,主要正則表達式還是應用於.NET平台,其他的沒有過的研究,但是這里只是一些思想。

       個人總結方法:

  1. 首先拿到原文本了解匹配的內容(這里就是要匹配的需求)
  2. 分解組成成分,考慮采用那些正則元字符等來寫(正則分析)
  3. 根據需求思考所有出現的情況(完整性)

下面從簡單例子着手:

例子一:匹配騰訊的QQ號

  我想大家對這個很了解,大家都在用QQ號,都知道QQ號的組成成分應該就是一連串的數字,OK,那么我們這就是對原文本的內容了解,下面我們要考慮的這些數字所有出現的可能騰訊的QQ號是從10000開始也就是從10000數字進行往上增加。那么我們就可以分解出來第一個數字不能是0開頭的,而且后面要是以4個數字以上。

  這樣我們就分析出來了所有出現的可能性。我們就將正則表達式進行分解。首先我們分解的是首位字符:必須要大於0,那么我們就采用字符類[1-9]這樣就搞定了首位字符,那么后面還剩下四位字符,這就好辦了,后面四位字符的規則是數字0開始至少有四位那么就可以這樣寫[0-9]{4,},這樣就表示數字從0開始9結束的任意字符至少重復4次。

  正則表達式:[1-9][0-9]{4,}

  原文本:10000

  匹配結果如下圖所示:

 

 

例子二:匹配下面的JSON返回的對象內容,匹配所有鍵值對

  原文本為:{"Dimension1":17.70,"Dimension2":16.70,"Level":"MN","Type":"LVGRM"},

  {"Dimension1":9.30,"Dimension2":11.90,"Level":"MN","Type":"DINRM"},

  {"Dimension1":11.20,"Dimension2":12.00,"Level":"MN","Type":"KITCH"},

  {"Dimension1":12.00,"Dimension2":11.20,"Level":"MN","Type":"EATAR"},

  {"Dimension1":12.20,"Dimension2":13.00,"Level":"MN","Type":"FAMRM"},

  {"Dimension1":15.50,"Dimension2":13.11,"Level":"ABV","Type":"MBDRM"},

  {"Dimension1":8.10,"Dimension2":6.50,"Level":"ABV","Type":"WICLO"},

  {"Dimension1":12.90,"Dimension2":11.50,"Level":"ABV","Type":"BDRM"},

  {"Dimension1":14.30,"Dimension2":14.10,"Level":"ABV","Type":"BDRM"},

  {"Dimension1":8.90,"Dimension2":5.10,"Level":"ABV","Type":"LAUND"},

  {"Dimension1":14.50,"Dimension2":28.70,"Level":"BST","Type":"RECRM"}

  首先我來說明一下這個比如第一行我們是將四對鍵值對一一匹配出來,Dimension1對應的是17.70,Dimension2對應的是16.70,Level對應的是MN,Type對應的是LVGRM。這樣清楚了要匹配內容,這里就是我們理解的要匹配的需求。這里我們就要分析這個正則中所有出現的可能性,我們發現”Dimension1”,” Dimension2”,” Level”,” Type”這些鍵里面有共同的特點,也就是兩邊是雙引號,中間是字符,通過分段分析之后我們可以得出前面一部分的正則表達式寫法是”[a-zA-Z0-9_]+”,注意了這樣匹配我們會將雙引號也會匹配進去,那么我們就會想到一個東西那就是將引號里面的內容進行分組,我們讀取出來的正則直接取出改組的內容即可(這就是考慮問題的完整性),這里我們將前半部分的正則表達式進行完善:”([a-zA-Z0-9_]+)”,好了前半部分的完成了再繼續往下分析整個結構,后面跟了一個:那么我們的正則后面也跟一個”([a-zA-Z0-9_]+)”:,看一下我們的分析的結果:

  接下來我們就來分析下一段也就是值得內容,這里我們看到了值分為了兩種情況:一種情況是小數,另一種情況是帶了雙引號的字符,那么我們怎樣將這兩個組合到一起是一個關鍵,那么我們就先來找一下他們的共同點,共同點就是他們都可以用正則的\w來進行匹配,那么我們就用字符類將所有可能出現的結果放在字符類里面就會出現[\w.],既然匹配的內容我們已經想辦法獲取到了,那么我們就會想到這個雙引號可有可無,那么我們就想到了懶惰的意思,那么我們就可以使用懶惰來進行完善這個正則表達式:”([a-zA-Z0-9_]+)”:”?([\w.]+)”?這樣我們的正則表達式就寫好了我們來看一下結果:

  附帶一張思維導圖,方便大家對上述分析的理解:

  簡單的例子咱們這邊就不做分享了,有時間自己來研究下就可以了,下面我們來說一個大家都認為用不上的平衡組的例子,第一篇(原理篇)文章的第九講講到平衡組里面有一個很明顯的案例就是說小括號匹配的問題,這里我就不詳細說明了。接下來我們來講解一個例子。

例子三:匹配SQL語句里面的case….when…語句

  下面是原文本:convert(decimal(18,4),(case replace(f3999 ,',','') when '' then '0' else isnull(replace(f3999 ,',',''),'0') end)),

  (case f2733 when 'house' then isnull(f2285,'') else isnull(f2833,'') end),

  (case f2733 when 'house' then isnull(f2576,'') else isnull(f3083,'') end),

  (case f2733 when 'house' then isnull(f2574,'') else isnull(f3081,'') end),

  (case f2733 when 'house' then isnull(f477,'') else isnull(f96,'') end),

  (case f2733 when 'house' then isnull(f714,'') else isnull(f404,'') end),

  下面我們就對這個正則進行分析,首先第一點我們要明白這個里面需求,從字面語句上去理解,看了原文本也應該清楚我們匹配的是case…when…語句,好了我們了解了我們要匹配什么東西,那么我們就來對正則的分析,分段進行分析,進行分析的時候我們能夠看到這里面有很多的小括號,如果我們這樣協寫正則的話”(原文本)”用單純的兩個括號來進行匹配的話僅僅會匹配從左到右最后一次匹配的括號里面的內容,所以這樣不是我們想要的結果,這時候我們要想一個整體的思路,這時候我們就要想到一個我們在原理篇談到的平衡組,用平衡組來進行如果碰到(就壓入堆棧,如果碰到)就彈出堆棧,最后判斷堆棧里面內容是不是為空的。好的,廢話不多說,我們來進行更詳細的分析,我們上面已經確定了整體的思路,下面分段進行分析首先我們單獨拿出一個SQL出來 case replace(f3999 ,',','') when '' then '0' else isnull(replace(f3999 ,',',''),'0') end通過這個語句我們可以先簡單的進行分析一下,這里面一共有三對括號,首先要壓入堆棧的是最開始的一個括號也就是replace后面的左括號”(”,先進入堆棧中,其次他在進行向后匹配的過程中,這個左括號找到了他的伴侶右括號,就將左括號彈出堆棧,繼續往下尋找又碰到了isnull后面的左括號壓入堆棧,后面繼續往下進行匹配的過程中該左括號A(在堆棧中的)暫時沒有找到他的伴侶,卻找到了他的情敵左括號B,於是兩個左括號不服相繼被壓入堆棧中進行對抗,不料在半路中左括號B於左括號A在爭奪情人的時候,左括號B遇上了他一見鍾情的右括號B,左括號B就退出了A於B的愛情Battle,於是愛河里面就剩下了孤零零的左括號A,獨自繼續尋找自己心愛的人,經過漫長的時間后左括號A終於找尋到了自己心愛的右括號A,兩人相伴終生,最后惡魔大人下來整治單身貴族,發現愛河里面已經沒有單相思了,惡魔就悄然離去。整體思路就是這樣,我們進行分段講解既然這里面的關鍵點就在於括號,那么我們就一括號來做划分,第一個左括號之前的內容還是比較容易的,所有組成成分中包含空格,字符兩種,這里要拋棄掉關鍵字段左右括號,那么我們的正則表達式①為:case [^\(\)]*,對應我們也將匹配的結果放上來:

  下面我們就要進入匹配第一個左括號了,我們將這個平衡組的名稱取名為battle吧,接下來就是將左括號壓入到battle中去,正則如下:(?’battle’\()接下來就是括號里面的內容了,經過我們的分析和詳細觀察源文本得出一個結果就是這個里面的內容一定不包括左右括號以外的所有內容,那么這個正則就會這樣寫[^\(\)]*,所以這兩句正則組合在一起就是(?’battle’\()[^\(\)]*,而這僅僅是愛情的開始,獨自一人在愛河中尋找真愛的人不僅僅只有他一個人,也許還會有很多,那么我們就將這些人划為一類人,那么就僅僅是在數量上的增加了,后面正則會是這樣((?’battle’\()[^\(\)]*)+既然我們已經找到了左邊的括號那么左邊的括號就不會耐得住寂寞獨自一人,他會千方百計去尋找他的另一半,那么當他遇到右括號的時候就飛出愛的海洋於相愛的人相伴一生,那么接下來的正則就應該是這樣遇到了右括號就將左括號彈出來,如下所示:(?’-battle’\))那么后面跟隨的依然是除了左右括號之外的東西[^\(\)]*,最后的正則是(?’-battle’\))[^\(\)]*,前面說了既然愛河中有很多單身的人,那么單身的人選擇的人應該也是有很多的但是自己心愛的人只有一個。最后的正則是這樣:((?’-battle’\))[^\(\)]*)+,通過左右括號比翼雙飛的結果我們可以看出他們是永遠的一對,永遠都是一起的那么他們就應該是整體的一組成員,對他們進行整合,(((?’battle’\()[^\(\)]*)+((?’-battle’\))[^\(\)]*)+)*也許括號的出現一對都沒有,也許會有一對或更多情侶的出現,所以后面加了數量詞,既然都成雙成對了,那么battle堆棧中就不應該出現單值出現的成員,我們要對battle堆棧進行檢驗,也就是這句正則(?(battle)(?!))最后將整體的正則進行完整性的整合就是:case[^\(\)]*(((?'battle'\()[^\(\)]*)+((?'-battle'\))[^\(\)]*)+)*(?(battle)(?!)),這樣我們的分析就完整了,下面來看一下整體匹配的結果:

 

  簡單將堆棧變化圖進行分析:

  

  最后將整體的思維導圖整理出來,供大家思考方便:

 

三、結束語

  零零散散的整理了三篇正則表達式的文章,如果有哪里不正確或者不完整的,希望能夠指正,通過這幾篇文章的總結,我相信看過這些文章的人正則有一定的提升,我自己本身的正則也有一定的提升!


免責聲明!

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



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