指尖上的正則表達式–入門篇

1)歷史和起源

正則表達式的「鼻祖」或許可一直追溯到科學家對人類神經系統工做原理的早期研究。美國新澤西州的Warren McCulloch和出生在美國底特律的Walter Pitts這兩位神經生理方面的科學家,研究出了一種用數學方式來描述神經網絡的新方法,他們創新地將神經系統中的神經元描述成了小而簡單的自動控制元,從而做出了一項偉大的工做革新。python

在1956 年,出生在被馬克•吐溫(Mark Twain)稱爲「美國最美麗的城市之一的」哈特福德市的一位名叫Stephen Kleene的數學科學家,他在Warren McCulloch和Walter Pitts早期工做的基礎之上,發表了一篇題目是《神經網事件的表示法》的論文,利用稱之爲正則集合的數學符號來描述此模型,引入了正則表達式的概念。正則表達式被做爲用來描述其稱之爲「正則集的代數」的一種表達式,於是採用了「正則表達式」這個術語。正則表達式

以後一段時間,人們發現能夠將這一工做成果應用於其餘方面。Ken Thompson就把這一成果應用於計算搜索算法的一些早期研究,Ken Thompson是 Unix的主要發明人,也就是大名鼎鼎的Unix之父。Unix之父將此符號系統引入編輯器QED,而後是Unix上的編輯器ed,並最終引入grep。Jeffrey Friedl 在其著做「Mastering Regular Expressions (2nd edition)」中對此做了進一步闡述講解,若是你但願更多瞭解正則表達式理論和歷史,推薦你看看這本書。    自此之後,正則表達式被普遍地應用到各類UNIX或相似於UNIX的工具中,如你們熟知的Perl。Perl的正則表達式源自於Henry Spencer編寫的regex,以後已演化成了pcre(Perl兼容正則表達式Perl Compatible Regular Expressions),pcre是一個由Philip Hazel開發的、爲不少現代工具所使用的庫。正則表達式的第一個實用應用程序即爲Unix中的 qed 編輯器。算法

而後,正則表達式在各類計算機語言或各類應用領域獲得了廣大的應用和發展,演變成爲目前計算機技術森林中的一隻形神美麗且聲音動聽的百靈鳥。    以上是關於正則表達式的起源和發展的歷史描述,到目前正則表達式在基於文本的編輯器和搜索工具中依然佔據這一個很是重要的地位。express

在最近的六十年中,正則表達式逐漸從模糊而深奧的數學概念,發展成爲在計算機各種工具和軟件包應用中的主要功能。不只僅衆多UNIX工具支持正則表達式,近二十年來,在WINDOW的陣營下,正則表達式的思想和應用在大部分 Windows 開發者工具包中獲得支持和嵌入應用!從正則式在Microsoft Visual Basic 6 或 Microsoft VBScript到.NET Framework中的探索和發展,WINDOWS系列產品對正則表達式的支持發展到無與倫比的高度,目前幾乎全部 Microsoft 開發者和全部.NET語言均可以使用正則表達式。若是你是一位接觸計算機語言的工做者,那麼你會在主流操做系統(*nix[Linux, Unix等]、Windows、HP、BeOS等)、目前主流的開發語言(PHP、C#、Java、C++、VB、Javascript、Ruby以及python等)、數以億萬計的各類應用軟件中,均可以看到正則表達式優美的舞姿。(摘自《百度百科--正則表達式》)編程

2) 正則表達式的定義

正則表達式是對字符串操做的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個「規則字符串」,這個「規則字符串」用來表達對字符串的一種過濾邏輯。數組

給定一個正則表達式和另外一個字符串,咱們能夠達到以下的目的:1. 給定的字符串是否符合正則表達式的過濾邏輯(稱做「匹配」);2. 能夠經過正則表達式,從字符串中獲取咱們想要的特定部分。瀏覽器

正則表達式的特色是:1. 靈活性、邏輯性和功能性很是的強;2. 能夠迅速地用極簡單的方式達到字符串的複雜控制。3. 對於剛接觸的人來講,比較晦澀難懂。網絡

因爲正則表達式主要應用對象是文本,所以它在各類文本編輯器場合都有應用,小到著名編輯器EditPlus,大到Microsoft Word、Visual Studio等大型編輯器,均可以使用正則表達式來處理文本內容。編輯器

3) 正則表達式的語法

正則表達式由一些普通字符和一些元字符組成,普通字符就是咱們平時常見的字符串、數字之類的,固然也包括一些常見的符號,等等。而元字符則能夠理解爲正則表達式引擎的保留字符,就像不少計算機語言中的保留字符同樣,他們在正則引擎中有特殊的意義,下面將介紹JavaScript中和正則相關的元字符以及API。(不一樣的計算機語言,對正則引擎的實現不是徹底一致的,因此,有些元字符和組合方式在JavaScript中不存在) 咱們將按照下面的分類將元字符一一列出:函數

3.1字面量字符( Literal Characters )

字符 描述 描述
f 換頁符 (u000C)
n 換行符 (u000A)
n 換行符 (u000A)
r 回車 (u000D)
o NUL字符 (u0000)
t 製表符 (u0009)
v 垂直製表符 (u000B)
xnn 由十六進制數nn指定的拉丁字符 x0A等價於n
uxxxx 由十六進行xxxx指定的Unicode字符 u0009等價與t
cX 控制字符(X的值必須是A-Z或a-z) cJ等價於換行符n

3.2字符類( Character Classes )

字符 描述 示例
[xyz] 匹配位於括號內的任意字符 [abc]匹配'plain'中的a
[^xyz] 匹配不在括號之中的任意字符 [^abc]匹配'plain'中的p
w 等價於[a-zA-Z0-9_] w匹配'sina'中的s
W 等價於[^a-zA-Z0-9_] w不能匹配'sina'
s 任何Unicode空白符 [ fnrtv]
S 任何非空白字符 [^ fnrtv]
d 等價於[0-9] d匹配'sina123'中的1
D 等價於[^0-9] D不能匹配'sina1'中的1
[b] 退格直接量(特例)  
除換行符和其它Unicode換行符以外的任意字符,[sS]匹配任意字符 a.c 匹配 "abc", "a1c", and "a-c".

3.3重複( Repetition )

字符 描述 示例
{n,m} 匹配至少n次,但不超過m次,n和m必須是非負整數,且n<=m
? 等價於 {0,1}
[abc]匹配'plain'中的a
{n,}

td>
匹配至少n次 o{2,} 不匹配'Bob'中的'o',但匹配'food'中的 o.
{n} 剛好匹配n次 o{2} 不匹配'Bob'中的'o',但匹配'food'中的o.
? 匹配0次或1次,等價於{0,1} zo? 匹配 "z" and "zo", 但不匹配"zoo".
+ 匹配1次或屢次,等價於{1,} zo+ 匹配 "zo" and "zoo", 但不匹配 "z".
* 匹配0次或屢次,等價於{0,} zo* 匹配 "z" 和 "zoo".

3.4非貪婪的重複(non-greedy)

字符 描述 示例
*?
+?
??
{n}?
{n,}? 
{n,m}?
在重複字符後加上問號,匹配模式就是非貪婪的匹配.這種模式會盡量少的對目標字符串進行匹配 o+? 匹配"oooo"中的一個"o", o+ 則匹配全部的 "o".
/a+?b/.exec('aaab')

3.5選擇、分組和引用

字符 描述 示例
|

(選擇)匹配該符號左邊或右邊的子表達式

(z|f)ood匹配zood或food
(pattern)

(分組)將幾個項目組合成一個單元,這個單元可由*,+,?和|等符號使用,並且還可記住和這個組合匹配的字符以供後面的引用使用

(A|B) [1-9] 匹配 "A5", 字母A被保存,可經過n或RegExp的$1-$9引用該值
(?:pattern) 只組合,不記憶

ai(?:r|R) 等價於air|aiR

n 和第n個分組第一次匹配的字符串匹配  

3.6指定匹配位置

字符 描述 示例
^

匹配字符串的開頭,在多行檢索中,匹配一行的開頭

^food&匹配以f開頭,d結尾的food,而不會匹配'eatfood222'中的'food'
$

匹配字符串的結尾,在多行檢索中,匹配一行的結尾

同上
b 匹配一個單詞的邊界

erb 匹配'never'中的'er',但不匹配'verb'中的'er'.

B 匹配非單詞邊界  
(?=pattern) 正向確定預查,在任何匹配pattern的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不須要獲取供之後使用 「Windows(?=95|98|NT|2000)」能匹配「Windows2000」中的「Windows」,但不能匹配「Windows3.1」中的「Windows」。預查不消耗字符,也就是說,在一個匹配發生後,在最後一次匹配以後當即開始下一次匹配的搜索,而不是從包含預查的字符以後開始
(?!pattern) 正向否認預查,在任何不匹配pattern的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不須要獲取供之後使用 「Windows(?!95|98|NT|2000)」能匹配「Windows3.1」中的「Windows」,但不能匹配「Windows2000」中的「Windows」。預查不消耗字符,也就是說,在一個匹配發生後,在最後一次匹配以後當即開始下一次匹配的搜索,而不是從包含預查的字符以後開始

3.7標誌

字符 描述
i 忽略大小寫
g 執行全局匹配,即找到全部的匹配,而不是在找到第一個匹配後中止
m

多行模式,^匹配一行的開頭和字符串的開頭,$匹配一行的結尾或字符串的結尾

4) JavaScript中的正則API

上一部分,咱們瞭解了正則表達式的語法,那麼,如何在JavaScript中構造一個正則表達式的對象呢?有如下兩種方法:

1.字面量表示法,例如:var reg = /d+/i; 就表示一個正則表達式的實例,這個寫法須要注意的地方是:正則表達式的主體部分,也就是示例中的 d+ ,必須位於「 / / 」之間,而標誌位則須要跟在結束 "/" 的後面。

2.實例化RegExp對象,例如: var reg = new RegExp( "d+", "igm" );第一個參數是表達式的主體,而第二個參數則是標誌位,此參數可選。 上面兩種方法能夠獲得正則表達式的實例,一般,咱們都使用第一種方式,即字面量的方式,這種方式比較直觀,第二種方式一般用來組合表達式,好比,經過用戶輸入的某個值,來構造表達式,例如:var input = 'this is a test'; var reg = new RegExp( "dw" + input,); 經過這種方式,咱們能夠組合成新的表達式,來達到咱們的目的。在使用這種方式時,須要注意對特殊字符的轉義和過濾,以避免遭受惡意攻擊。 JavaScript中,除了正則表達式對象外,字符串也和正則表達式息息相關。能夠說,RegExp和String 是密不可分的,缺一不可。因此,和正則相關的API就是RegExp對象和String對象的一些API。

首先是RegExp對象,該對象的實例中,有三個方法和正則表達式相關,分別是test( ),exec( )和compile( )。而String對象中和正則相關的方法則包括:match( ), replace( ), search( ), split( ),接下來會對這些方法作詳細介紹。

4.1 exec( )

exec( ) 方法檢索字符串中的指定值。返回值是被找到的值。若是沒有發現匹配,則返回 null。

例子1:

var patt1 = new RegExp("e"); //  var patt1 = /e/;
document.write( patt1.exec("The best things in life are free") ); //output : e

從上面的例子中能夠看出,exec( )方法接收一個參數,類型爲字符串,能夠簡單的理解爲:我是一個正則表達式實例,請給我一個字符串來測測吧,因而,咱們知足了它的願望,把目標字符串丟給它。

若是匹配成功,該方法的返回結果是一個數組[array],該數組的第一個元素則是匹配的字符串,後面的元素則是表達式分組所捕獲到的值,分組爲1,則是該數組中的第一個元素,依次類推。若沒有分組,該數組只包含一個元素。固然,該數組還有另外3個屬性,input,index和lastIndex。若沒有匹配成功,則返回null。

input屬性表示目標字符串。

index屬性表示匹配到的位置。

lastIndex屬性表示上一次匹配後的位置。

另外,須要注意的是,若表達式實例中包含了全局(g)標誌位,則會從 lastIndex 所標記的位置開始查找,而不會從字符串的開始位置進行。因此,咱們能夠屢次調用exec( )方法,好比:

function RegExpTest()
{
   var src = "The quick brown fox jumps over the lazy dog.";

   // Create regular expression pattern with a global flag.
   var re = /w+/g;

   // Get the next word, starting at the position of lastindex.
   var arr;
   while ((arr = re.exec(src)) != null)
      {
      // New line:
      document.write ("<br />");  
      document.write (arr.index + "-" + arr.lastIndex + " ");
      document.write (arr[0]);
      }
}

詳細描述請參考:

http://msdn.microsoft.com/en-us/library/z908hy33(v=vs.94).aspx

4.2 test( )

test( ) 方法比exec( )方法簡單,該方法只會返回一個Boolean值,若是匹配成功,則返回true,不然,返回false。可參考下面的示例:

function TestDemo(re, teststring)
{
   // Test string for existence of regular expression.
   var found = re.test(teststring)

   // Format the output.
   var s = "";
   s += "'" + teststring + "'"

   if (found)
      s += " contains ";
   else
      s += " does not contain ";
      
   s += "'" + re.source + "'"
   return(s);
}

詳細描述請參考:

http://msdn.microsoft.com/en-us/library/a55e5s6b(v=vs.94).aspx

4.3 match( )

須要注意的是,該方法的參數,也就是正則表達式添加了全局( g )標誌位時的變化。若是沒有添加全局標誌位,返回結果和exec( )方法的返回值同樣,但不包含全部的屬性。

詳細描述請參考:
http://msdn.microsoft.com/en-us/library/7df7sf4x(v=vs.94).aspx

4.4 replace( )

該方法是字符串中很是強有力的方法,它接收兩個參數,第一個參數爲表達式,也能夠直接傳入字符串,該方法在內部會自動將字符串轉換爲正則表達式;第二個參數是想要替換成的字符串,該參數能夠爲一個函數,可是該函數的返回值必須爲字符串。具體用法請參考 http://msdn.microsoft.com/en-us/library/t0kbytzc(v=vs.94).aspx

4.5 split( )

該方法能夠按照傳遞的參數對字符串進行分割,會返回一個數組,裏面包含了分割後的元素。通常用法是直接傳入字符串進行分割,固然,也能夠傳入正則表達式,按表達式分割,詳細信息請參考: http://msdn.microsoft.com/en-us/library/t5az126b(v=vs.94).aspx

4.6其它

compile( ),search( )等方法,在平常使用中較少使用,大體瞭解一下便可。

5) 實例解析

你們能夠參考【正則表達式經典實例】,請參考附件。

小結

以上主要講解了正則表達式的基本語法和經常使用API,對於如何構造複雜的表達式和表達式的匹配原理,本文並未涉及。說實話,正則表達式自己確實晦澀難懂,比較拗口,你們需在平時,多多溫習這些基礎的語法和API。

另外,能夠用一些工具來輔助咱們寫出嚴謹的正則表達式,好比:RegexBuddy或者一些在線的應用。固然,還有瀏覽器的控制檯,能夠在裏面很方便的進行測試。

在平常的開發中,千萬不要在正則上鑽牛角尖,由於咱們能夠利用其它API,達到一樣的目的。並且,太過複雜的表達式,效率可能較低,並且,對於之後的維護人員來講,也是很是不方便維護的。

但千萬不要淺嘗輒止,應該繼續深挖正則中的思想,正是這些基礎的思想,才能幫我咱們在編程上更上層樓。

參考信息
http://msdn.microsoft.com/en-us/library/z908hy33(v=vs.94).aspx
exec()

http://msdn.microsoft.com/en-us/library/a55e5s6b(v=vs.94).aspx
test()

http://msdn.microsoft.com/en-us/library/7df7sf4x(v=vs.94).aspx
match()

http://msdn.microsoft.com/en-us/library/t0kbytzc(v=vs.94).aspx
replace()

http://www.w3school.com.cn/js/jsref_obj_regexp.asp
regexp obj

精通正則表達式(第三版)
正則表達式經典實例

轉:http://ued.sina.com.cn/?p=1121

相關文章
相關標籤/搜索