1. 程式人生 > >vb.net正則表示式快速入門(1)

vb.net正則表示式快速入門(1)

深入淺出之正則表示式   

作者:lzmtw

注:JanGoyvaerts為RegexBuddy寫的教程的譯文

前言:半年前我對正則表示式產生了興趣,在網上查詢過不少資料,看過不少的教程,最後在使用一個正則表示式工具RegexBuddy時發現他的教程寫的非常好,可以說是我目前見過最好的正則表示式教程。於是一直想把他翻譯過來。這個願望直到這個五一長假才得以實現,結果就有了這篇文章。關於本文的名字,使用“深入淺出”似乎已經太俗。但是通讀原文以後,覺得只有用“深入淺出”才能準確的表達出該教程給我的感受,所以也就不能免俗了。

本文是JanGoyvaerts為RegexBuddy寫的教程的譯文,版權歸原作者所有,歡迎轉載。但是為了尊重原作者和譯者的勞動,請註明出處!謝謝!




1.什麼是正則表示式

基本說來,正則表示式是一種用來描述一定數量文字的模式

Regex代表RegularExpress。本文將用

         < <regex> > 來表示一段具體的正則表示式。

一段文字就是最基本的模式,簡單的匹配相同的文字。


2.不同的正則表示式引擎

正則表示式引擎是一種可以處理正則表示式的軟體。通常,引擎是更大的應用程式的一部分。

在軟體世界,不同的正則表示式並不互相相容。

本教程會集中討論Perl5型別的引擎,因為這種引擎是應用最廣泛的引擎。

同時我們也會提到一些和其他引擎的區別。許多近代的引擎都很類似,但不完全一樣。例如.NET正則庫

,JDK正則包。


3.文字元號

最基本的正則表示式由單個文字元號組成。如 

       < <a> > ,它將匹配字串中第一次出現的字元“a”。

如對字串“Jack is a boy”。“J”後的“a”將被匹配。而第二個“a”將不會被匹配。

正則表示式也可以匹配第二個“a”,這必須是你告訴正則表示式引擎從第一次匹配的地方開始搜尋。

在文字編輯器中,你可以使用“查詢下一個”。在程式語言中,會有一個函式可以使你從前一次匹配的位置開始繼續向後搜尋。類似的, 

        <<cat>>會匹配“About cats and dogs”中的“cat”。

這等於是告訴正則表示式引擎,找到一個 < <c> > ,緊跟一個 < <a> > ,再跟一個 < <t> > 。

要注意,正則表示式引擎預設是大小寫敏感的。除非你告訴引擎忽略大小寫,否則 < <cat> > 不會匹配“Cat”。

特殊字元對於文字字元,有11個字元被保留作特殊用途。

他們是:[]\^$. ¦?* ()這些特殊字元也被稱作元字元。

如果你想在正則表示式中將這些字元用作文字字元,你需要用反斜槓“\”對其進行換碼(escape)。

例如你想匹配“1 1=2”,正確的表示式為 < <1\ 1=2> >
需要注意的是, < <1 1=2> > 也是有效的正則表示式。但它不會匹配“1 1=2”,而會匹配“123 111=234”中的“111=2”。

因為“ ”在這裡表示特殊含義(重複1次到多次)。

在程式語言中,要注意,一些特殊的字元會先被編譯器處理,然後再傳遞給正則引擎。

因此正則表示式 

          < <1\ 2=2> > 在C 中要寫成“1\\ 1=2”。

為了匹配“C:\temp”,你要用正則表示式

          < <C:\\temp> > 。而在C 中,正則表示式則變成了“C:\\\\temp”。
不可顯示字元可以使用特殊字元序列來代表某些不可顯示字元:

          < <\t> > 代表Tab(0x09)

          < <\r> > 代表回車符(0x0D)

          < <\n> > 代表換行符(0x0A)

要注意的是Windows中文字檔案使用“\r\n”來結束一行而Unix使用“\n”。


4.正則表示式引擎的內部工作機制

知道正則表示式引擎是如何工作的有助於你很快理解為何某個正則表示式不像你期望的那樣工作。

有兩種型別的引擎:文字導向(text-directed)的引擎和正則導向(regex-directed)的引擎。

JeffreyFriedl把他們稱作DFA和NFA引擎。本文談到的是正則導向的引擎

這是因為一些非常有用的特性,如“惰性”量詞(lazyquantifiers)和反向引用(backreferences),只能在正則導向的引擎中實現。

所以毫不意外這種引擎是目前最流行的引擎。你可以輕易分辨出所使用的引擎是文字導向還是正則導向。

如果反向引用或“惰性”量詞被實現,則可以肯定你使用的引擎是正則導向的。

你可以作如下測試:將正則表示式 

             < <regex ¦regexnot> > 應用到字串“regexnot”。

如果匹配的結果是regex,則引擎是正則導向的。如果結果是regexnot,則是文字導向的。

因為正則導向的引擎是“猴急”的,它會很急切的進行表功,報告它找到的第一個匹配。

正則導向的引擎總是返回最左邊的匹配,這是需要你理解的很重要的一點:即使以後有可能發現一個“更好”的匹配,正則導向的引擎也總是返回最左邊的匹配。

當把 < <cat> > 應用到“He captured a catfish for his cat”,引擎先比較 < <c> > 和“H”,結果失敗了。

於是引擎再比較 < <c> > 和“e”,也失敗了。直到第四個字元, < <c> > 匹配了“c”。 < <a> > 匹配了第五個字元。

到第六個字元 < <t> > 沒能匹配“p”,也失敗了。引擎再繼續從第五個字元重新檢查匹配性。

直到第十五個字元開始, < <cat> > 匹配上了“catfish”中的“cat”,正則表示式引擎急切的返回第一個匹配的結果,而不會再繼續查詢是否有其他更好的匹配。


5.字符集

字符集是由一對方括號“[]”括起來的字元集合。

使用字符集,你可以告訴正則表示式引擎僅僅匹配多個字元中的一個。如果你想匹配一個“a”或一個“e”,使用 

           < <[ae]> > 。

你可以使用 < <gr[ae]y> > 匹配gray或grey。這在你不確定你要搜尋的字元是採用美國英語還是英國英語時特別有用。

相反, < <gr[ae]y> > 將不會匹配graay或graey。

字符集中的字元順序並沒有什麼關係,結果都是相同的。你可以使用連字元“-”定義一個字元範圍作為字符集。 

           < <[0-9]> > 匹配0到9之間的單個數字。你可以使用不止一個範圍。

           < <[0-9a-fA-F]> > 匹配單個的十六進位制數字,並且大小寫不敏感。你也可以結合範圍定義與單個字元定義。

           < <[0-9a-fxA-FX]> > 匹配一個十六進位制數字或字母X。

再次強調一下,字元和範圍定義的先後順序對結果沒有影響。

字符集的一些應用查詢一個可能有拼寫錯誤的單詞,比如 

           < <sep[ae]r[ae]te> > 或 < <li[cs]en[cs]e> > 。

查詢程式語言的識別符號, < <A-Za-z_][A-Za-z_0-9]*> > 。(*表示重複0或多次)

查詢C風格的十六進位制數 < <0[xX][A-Fa-f0-9] > > 。( 表示重複一次或多次)


取反字符集在左方括號“[”後面緊跟一個尖括號“^”,將會對字符集取反。結果是字符集將匹配任何不在方括號中的字元。

不像“.”,取反字符集是可以匹配回車換行符的。

需要記住的很重要的一點是,取反字符集必須要匹配一個字元。 < <q[^u]> > 並不意味著:匹配一個q,後面沒有u跟著。

它意味著:匹配一個q,後面跟著一個不是u的字元。所以它不會匹配“Iraq”中的q,而會匹配“Iraq is a country”中的q和一個空格符

事實上,空格符是匹配中的一部分,因為它是一個“不是u的字元”。

如果你只想匹配一個q,條件是q後面有一個不是u的字元,我們可以用後面將講到的向前檢視來解決。


字符集中的元字元需要注意的是,在字符集中只有4個字元具有特殊含義。

它們是:“]\^-”。“]”代表字符集定義的結束;

            “\”代表轉義;

            “^”代表取反;

            “-”代表範圍定義。

       其他常見的元字元在字符集定義內部都是正常字元,不需要轉義。

例如,要搜尋星號*或加號,你可以用 < <[ *]> > 。當然,如果你對那些通常的元字元進行轉義,你的正則表示式一樣會工作得很好,但是這會降低可讀性

在字符集定義中為了將反斜槓“\”作為一個文字字元而非特殊含義的字元,你需要用另一個反斜槓對它進行轉義。 

     < <[\\x]> > 將會匹配一個反斜槓和一個X。

“]^-”都可以用反斜槓進行轉義,或者將他們放在一個不可能使用到他們特殊含義的位置。

我們推薦後者,因為這樣可以增加可讀性。比如對於字元“^”,將它放在除了左括號“[”後面的位置,使用的都是文字字元含義而非取反含義。

如 < <[x^]> > 會匹配一個x或^。

    < <[]x]> > 會匹配一個“]”或“x”。

    < <[-x]> > 或 < <[x-]> > 都會匹配一個“-”或“x”。

字符集的簡寫因為一些字符集非常常用,所以有一些簡寫方式。 

      < <\d> > 代表 < <[0-9]> > ; 

      < <\w> > 代表單詞字元。

這個是隨正則表示式實現的不同而有些差異。絕大多數的正則表示式實現的單詞字符集都包含了 < <A-Za-z0-9_]> > 。 

      < <\s> > 代表“白字元”。

這個也是和不同的實現有關的。在絕大多數的實現中,都包含了空格符和Tab符,以及回車換行符 < <\r\n> > 。

字符集的縮寫形式可以用在方括號之內或之外。

      < <\s\d> > 匹配一個白字元後面緊跟一個數字。 

      < <[\s\d]> > 匹配單個白字元或數字。 

      < <[\da-fA-F]> > 將匹配一個十六進位制數字。

取反字符集的簡寫 (注意大小寫

      < <[\S]> > = < <[^\s]> >

      < <[\W]> > = < <[^\w]> > 

      < <[\D]> > = < <[^\d]> >
字符集的重複如果你用“?* ”操作符來重複一個字符集,你將會重複整個字符集。而不僅是它匹配的那個字元。

正則表示式 < <[0-9] > > 會匹配837以及222。如果你僅僅想重複被匹配的那個字元,可以用向後引用達到目的。我們以後將講到向後引用