天天看點

正規表達式初探

本章主要想和大家分享下正規表達式的一些基礎用法,希望能夠對一些小白有所幫助,也為了防止自己以後遺忘相關知識點。

本章主要想和大家分享下正規表達式的一些基礎用法,希望能夠對一些小白有所幫助,也為了防止自己以後遺忘相關知識點,下面我們正式進入主題。

一、正規表達式

  1、正規表達式是由普通字元(例如字元 a 到 z)以及特殊字元(稱為元字元)組成的文字模式。

  2、正規表達式作為一個模闆,将某個字元模式與所搜尋的字元串進行比對。

  3、在編寫處理字元串的程式或網頁時,經常會有查找或替換符合某些複雜規則的字元串的需要。

  4、正規表達式就是記錄文本規則的代碼。

  作用:

    1、查找資料

    2、替換資料

  正規表達式能做什麼(字元串的比對、字元串的提取、字元串的替換)

二、正規表達式的構成

  1、普通字元(如果直接寫多個普通字元,則會被當做一個整體的字元串來比對)

    這包括所有的大小寫字母字元,所有數字,所有标點符号以及一些特殊符号。

    例如:Hello world xyh666

  2、定義字元集(取值範圍)(該點都是比對單個字元,要想比對字元串需要結合限定符來實作)

    [a-e] 表示a到e這些字元中的某一個字元

    [aeiou] 表示aeiou這5個字元其中的某一個字元

    [a-zA-Z] 表示大寫、小寫字母中的某一個字元

    [0-9] 表示0到9之間某一個數字

    ^ 代表非

    [^lsjd]  :不是中括号中的任意一個字元

    [^a-f]  :a-f範圍外的任意一個字元

  3、組合字元(大寫表示非)(該點都是比對單個字元,要想比對字元串需要結合限定符來實作)

    \d  :比對一個數字字元。等價于[0-9]。

    \D  :比對一個非數字字元。等價于[^0-9]。

    \w  :比對一個字母或一個數字或一個下劃線或一個漢字。

    \W  :比對一個非字母、非數字、非下劃線和非漢字的字元。

    \s  :比對一個任意的空白符,包括空格、制表符、換頁符等等。等價于[ \f\n\r\t\v]。

    \S  :比對任意一個非空白符。等價于[^ \f\n\r\t\v]。

    \b  :比對單詞的開始或結束的位置。

    \B  :比對不是單詞開頭或結束的位置。

  4、特殊字元

    $  :表示字元串的結尾位置(以什麼結尾)

    ^  :表示字元串的開始位置(以什麼開始)(在取值範圍中還表示非)

    .  :一個點表示比對一個除換行符 \n之外的任何單字元(比對單個字元,要想比對字元串需要結合限定符來實作)

    |  :或者的意思,指明兩項之間的一個選擇 與[...]類似

    \  :這個符号是用來轉義的

    ( )  :分組,标記一個子表達式的開始和結束位置

  5、常用限定符

    =================比對次數=================

    {m}  :其前一單元嚴格出現m次(重複m次)

    {m,}  :其前一單元出現至少m次(重複m次或更多次)

    {m,n}  :其前一單元出現至少m次,最多n次(重複m到n次)

    =======================================

    =================多次比對=================

    *   :其前面那個單元出現0次或任意次數(重複零次或更多次)

    +   : 其前面那個單元出現1次或1次以上 至少比對一次(重複一次或更多次)

    ?  : 其前面那個單元出現0次或1次(重複零次或一次)懶惰比對(盡可能短比對)

    =======================================

  6、貪婪與懶惰(貪婪模式和非貪婪模式)(盡可能長比對和盡可能短比對)

    *? 重複任意次,但盡可能少重複

    +? 重複1次或更多次,但盡可能少重複

    ?? 重複0次或1次,但盡可能少重複

    {n,m}? 重複n到m次,但盡可能少重複

    {n,}? 重複n次以上,但盡可能少重複

  7、分組

    當用()定義了一個正規表達式組後,正則引擎則會把被比對的組按照順序編号,存入緩存。

    預設情況下,每個分組會自動擁有一個組号,規則是:從左向右,以分組的左括号為标志,第一個出現的分組的組号為1,第二個為2,以此類推。

    我們可以通過“\數字”的方式進行引用已經存入緩存的組。\1引用第一個比對的組,\2引用第二個組,以此類推。

    括号内的内容會被當成一個整體進行比對。

  8、非擷取比對和預查(零寬斷言)

    非擷取比對:是指正則引擎不會把被比對的組存入緩存,我們也無法通過“\數字”的方式進行引用我們的組。

    預查:預查不消耗字元,也就是說,在一個比對發生後,在最後一次比對之後立即開始下一次比對的搜尋,而不是從包含預查的字元之後開始。(即用來預查的表達式字元串不會被消耗,它隻是用于指定一個位置)

    零寬斷言:用于查找在某些内容(但并不包括這些内容)之前或之後的東西,也就是說它們像\b,^,$那樣用于指定一個位置,這個位置應該滿足一定的條件(即斷言),是以它們也被稱為零寬斷言。

    ===========================================================================================

    (?=exp)也叫零寬度正預測先行斷言,它斷言自身出現的位置的後面能比對表達式exp。比如\b\w+(?=ing\b),比對以ing結尾的單詞的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.時,它會比對sing和danc。

    (?<=exp)也叫零寬度正回顧後發斷言,它斷言自身出現的位置的前面能比對表達式exp。比如(?<=\bre)\w+\b會比對以re開頭的單詞的後半部分(除了re以外的部分),例如在查找reading a book時,它比對ading。

    (?:pattern) 非擷取比對,比對pattern但不擷取比對結果,不進行存儲供以後使用。這在使用或字元“(|)”來組合一個模式的各個部分時很有用。例如“industr(?:y|ies)”就是一個比“industry|industries”更簡略的表達式。

    (?=pattern) 非擷取比對,正向肯定預查,在任何比對pattern的字元串開始處比對查找字元串,該比對不需要擷取供以後使用。例如,“Windows(?=95|98|NT|2000)”能比對“Windows2000”中的“Windows”,但不能比對“Windows3.1”中的“Windows”。預查不消耗字元,也就是說,在一個比對發生後,在最後一次比對之後立即開始下一次比對的搜尋,而不是從包含預查的字元之後開始。

    (?!pattern) 非擷取比對,正向否定預查,在任何不比對pattern的字元串開始處比對查找字元串,該比對不需要擷取供以後使用。例如“Windows(?!95|98|NT|2000)”能比對“Windows3.1”中的“Windows”,但不能比對“Windows2000”中的“Windows”。

    (?<=pattern) 非擷取比對,反向肯定預查,與正向肯定預查類似,隻是方向相反。例如,“(?<=95|98|NT|2000)Windows”能比對“2000Windows”中的“Windows”,但不能比對“3.1Windows”中的“Windows”。

    (?<!patte_n) 非擷取比對,反向否定預查,與正向否定預查類似,隻是方向相反。例如“(?<!95|98|NT|2000)Windows”能比對“3.1Windows”中的“Windows”,但不能比對“2000Windows”中的“Windows”。

  9、其他常用正則比對

    比對中文字元的正規表達式:[\u4e00-\u9fa5]

    比對雙位元組字元(包括漢字在内):[^\x00-\xff]

    比對中文、英文字母和數字及_:^[\u4e00-\u9fa5_a-zA-Z0-9]+$或[\u4e00-\u9fa5_a-zA-Z0-9_]{4,10}

    隻含有漢字、數字、字母、下劃線并且不能以下劃線開頭和結尾:^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$

    (?!_)表示不能以_開頭,(?!.*?_$)表示不能以_結尾

三、C#代碼調用正規表達式

命名空間 System.Text.RegularExpressions
    
    1、new Regex(正規表達式).IsMatch(要比對的字元串)   傳回bool
    2、Regex.Match
        Match match = Regex.Match("age=30", @"^(.+)=(.+)$");
        if (match.Success)
        {
            Console.WriteLine(match.Groups[0].Value);//第0組 輸出完整的字元串 age=30
            Console.WriteLine(match.Groups[1].Value);//第1組 age
            Console.WriteLine(match.Groups[2].Value);//第2組 30
        }
    3、Regex.Matches
        StringBuilder sb = new StringBuilder();
        sb.Append("<Name>張三</Name>\r\n<Name>李四</Name>\r\n<Name>王五</Name>");

        MatchCollection mc = Regex.Matches(sb.ToString(), @"(?<=<Name>).*(?=</Name>)");
        foreach (Match m in mc)
        {
            Console.WriteLine(m.Value);
        }      

四、示例說明

接下來針對第二大點的内容我們舉些例子來說明:

示例1(普通字元):

我們用 xyh 來比對 xyh123 如下圖所示:

正規表達式初探

 從上面的正規表達式測試器比對的結果可以看出:如果直接寫多個普通字元,則會被當做一個整體的字元串來比對。

示例2(元字元和限定符):

我們用 \d 來比對 xyh123 如下圖所示:

正規表達式初探

 從比對的結果可以發現\d隻是比對單個數字,是以有三個結果,分别為1、2、3,那如果想比對一整個字元串123要怎麼辦呢?此時就要結合限定符來實作了。繼續來看下下面的一張圖。

正規表達式初探

 從圖中可以看出結合限定符後就可以實作比對到123這個字元串了。

示例3(普通字元和元字元組合):

我們用 https://www\..+\.com 來比對這麼一句話:https://www.jd.com兩個連結https://www.taobao.com  如下圖所示:

正規表達式初探

 可以發現比對的結果為完整的一整句話,那為什麼不是比對出2個結果分别為 https://www.jd.com 和 https://www.taobao.com 呢?

 那是因為預設情況下正規表達式采用貪婪模式比對(即盡可能多比對),是以比對出了完整的一句話,此時可以用?來實作非貪婪模式比對(即盡可能少比對),如下圖所示:

正規表達式初探

 這樣就比對出了2個結果

示例4(分組):

 我們用 (abc)\1 來比對 abcabc666 如下圖所示:

正規表達式初探

 從圖中可以看出比對結果為abcabc,為什麼會是這樣呢?首先我們分組(abc)比對到存入緩存中的值為abc,通過\1的方式就取到了存入緩存中的第1個分組值abc,這個分組值abc與原來分組(abc)比對到的字元串abc組成新的比對字元串abcabc,用新的比對字元串abcabc去比對abcabc666得到的比對結果就是abcabc了。

示例5(非擷取比對):

非擷取比對(?:pattern)如下圖所示:

正規表達式初探
正規表達式初探

 從圖中可以看出非擷取比對,比對pattern但不擷取比對結果,不進行存儲供以後使用。是以無法通過“\數字”的方式來擷取。

示例6(預查和零寬斷言):

預查不消耗字元,它隻是用于指定一個位置,如下圖所示:

正規表達式初探

 從圖中可以看出用 ab(?=a) 來比對 ababa123 時會得到兩個結果而不是一個結果,那是因為預查不消耗字元(即不會消耗用來預查用的表達式exp對應的字元),它隻是用于指定一個位置,是以在第3個位置的a(即第2個a)沒有被消耗掉。當比對到第1個結果ab後會從第3個位置的a(即第2個a)開始查找下一個能比對的字元串,而不是從第4個位置的b(即第2個b)開始查找,這就解釋了為什麼會比對到2個結果了。

PS:本文僅是個人見解 ,如有表述錯誤歡迎評論指正!

正規表達式測試器:

連結:https://pan.baidu.com/s/1CwyrLH2dwbBk1KVi2FCGDw 
提取碼:nwyc      

版權聲明:本文部分描述摘自網絡,如有雷同純屬巧合,如有侵權請及時聯系本人修改,謝謝!!!

繼續閱讀