正則表達式學習總結

1、背景

工做上遇到一個這樣的需求:javascript

用正則表達式將一個字符串中的span標籤替換爲img標籤,並將原span標籤的內容放到img標籤的src中,問題詳細描述:點我html

看到這個需求,我知道應該能夠用正則表達式,但是因爲以前沒怎麼用,一想到正則表達式就頭大,一堆各類各樣的特殊符號,彷佛沒有規律可循,有點難以理解。不過知道本身不能逃避,因而本身就去嘗試怎麼寫這個正則表達式來解決個人需求,上述中提到的問題詳細描述,大概就是我思考的過程,問題提出後立馬有人解答,看完他們的答案後,慚愧,感受到本身知識的欠缺,再不學習就老了(┬_┬)java

2、正則表達式基礎

2.1 元字符介紹

  • "^":^會匹配行或者字符串的起始位置,有時還會匹配整個文檔的起始位置。
  • "$":$會匹配行或字符串的結尾。
  • "\b":不會消耗任何字符只匹配一個位置,經常使用於匹配單詞邊界 如:我想從字符串中"This is Regex"匹配單獨的單詞 "is" 正則就要寫成:"This is Regex".match(/\bis\b/); "\b" 不會匹配is 兩邊的字符,但它會識別is 兩邊是否爲單詞的邊界。
  • "\d":匹配數字。
  • "\w":匹配字母,數字,下劃線。等價於'[A-Za-z0-9_]'。
  • "\s":匹配空格。
  • ".":匹配除了換行符之外的任何字符。
  • "[a-zA-Z]":字符組 匹配包含括號內元素的字符。
  • 幾種反義:改爲大寫,意思就與原來的相反。
    如:
    "\W":匹配任何非單詞字符。等價於'[^A-Za-z0-9_]'。
    "[^abc]":匹配除了abc之外的任意字符。正則表達式

  • 字符轉義:在正則表達式中元字符是有特殊的含義的,當咱們要匹配元字符自己時,就須要用到字符轉義,如:/\./.test("."); // truesegmentfault

2.2 量詞

2.2.1 經常使用量詞

  • "*"(貪婪)重複零次或更多,貪婪量詞會首先匹配整個字符串,嘗試匹配時,它會選定儘量多的內容,若是 失敗則回退一個字符,而後再次嘗試回退的過程就叫作回溯,它會每次回退一個字符,直到找到匹配的內容或者沒有字符能夠回退。如:
    "aaaaaa".match(/a*/) // ["aaaaaa"]
  • "?"(懶惰)重複零次或一次,懶惰量詞使用另外一種方式匹配,它從目標的起始位置開始嘗試匹配,每次檢查一個字符,並尋找它要匹配的內容,如此循環直到字符結尾處。如:"aaaaaa".match(/a?/) // ["a"]
  • "+"(佔有)重複零次或更屢次,佔有量詞會覆蓋事個目標字符串,而後嘗試尋找匹配內容 ,但它只嘗試一次,不會回溯。如:
    "aaaaaa".match(/a+/) // ["aaaaaa"]
  • "{n}"重複n次;如:
    "aaaaaa".match(/a{3}/) // ["aaa"]
  • "{n,m}"重複n到m次;如:
    "aaaaaa".match(/a{3,4}/) // ["aaaa"]
  • "{n,}" 重複n次或更屢次;如:
    "aaaaaa".match(/a{3,}/) // ["aaaaaa"]

2.2.1 懶惰限定符

  • "*?" 重複任意次,但儘量少重複;如:"aabab".match(/a.*?b/) // ["aab"] 爲何第一個匹配是aab(第一到第三個字符)而不是ab(第二到第三個字符)?簡單地說,由於正則表達式有另外一條規則,比懶惰/貪婪規則的優先級更高:最早開始的匹配擁有最高的優先權
  • "+?" 重複1次或更屢次,但儘量少重複,與上面同樣,只是至少要重複1次。如:"aabab".match(/a.+?b/) // ["aab"]
  • "??" 重複0次或1次,但儘量少重複。如:"aabab".match(/a.??b/) // ["aab"]
  • "{n,m}?" 重複n到m次,但儘量少重複。如:"aaa".match(/a{1,3}?/) // ["a"]
  • "{n,}?" 重複n次以上,但儘量少重複。如:"aaa".match(/a{1,}?/) // ["a"]

2.2.2 處理選項

  • javascript中正則表達式支持的正則表達式有三個,g、i、m,分別表明全局匹配、忽略大小寫、多行模式。三種屬性能夠自由組合共存。
  • 在默認的模式下,元字符 ^ 和 $ 分別匹配字符串的開頭和結尾處,模式 m 改變了這倆元字符的定義,讓他們匹配一行的開頭和結尾。

3、正則進階

3.1 捕獲分組

正則表達式一個最重要的特性就是將匹配成功的模式的某部分進行存儲供之後使用這一能力。對一個正則表達式模式或部分模式兩邊添加圓括號將致使這部分表達式存儲到一個臨時緩衝區中。(可使用非捕獲元字符 '?:', '?=', 或 '?!' 來忽略對這部分正則表達式的保存。)數組

所捕獲的每一個子匹配都按照在正則表達式模式中從左至右所遇到的內容存儲。存儲子匹配的緩衝區編號從 1 開始,連續編號直至最大 99 個子表達式。每一個緩衝區均可以使用 '\n' 訪問,其中 n 爲一個標識特定緩衝區的一位或兩位十進制數。函數

後向引用一個最簡單,最有用的應用是提供了肯定文字中連續出現兩個相同單詞的位置的能力。學習

舉個例子:測試

/(\b[a-zA-Z]+\b)\s+\1\b/.exec(" asd sf  hello hello asd"); //["hello hello", "hello"]

解釋這個例子:spa

一、(\b[a-zA-Z]+\b) 是一個捕獲分組,它捕獲全部的單詞,

" asd sf  hello hello asd".match(/(\b[a-zA-Z]+\b)/g) // ["asd", "sf", "hello", "hello", "asd"]

注:加上/g這個處理選項是便於我理解,沒有這個選項的時候,只輸出第一個單詞asd。
二、\s加了一個空格限制條件,因此最後一個單詞被排除,

" asd sf  hello hello asd".match(/(\b[a-zA-Z]+\b)\s/g) \\ ["asd ", "sf ", "hello ", "hello "]

三、"\1"後向引用,

" asd sf  hello hello asd".match(/(\b[a-zA-Z]+\b)\s+\1\b/g) \\ ["hello hello"]

說實話,這個例子花了我很長時間去理解,有一點點想通,感受這個概念看起來容易,寫起來並不容易啊。

3.2 捕獲分組常有的用法(斷言)

  • "(exp)" 匹配exp,並捕獲文本到自動命名的組裏;如:
/(hello)\sworld/.exec("asdadasd hello world asdasd") // ["hello world", "hello"]
  • "(?:exp)" 匹配exp,不捕獲匹配的文本,也不給此分組分配組號;如:
/(?:hello)\sworld/.exec("asdadasd hello world asdasd")  // ["hello world"]
  • "(?=exp)" 用來捕獲exp前面的字符,分組中的內容不會被捕獲,也不分配組號;如:
/hello\s(?=world)/.exec("asdadasd hello world asdasd")  // ["hello "]
  • "(?!exp)" 捕獲後面不是exp的字符,一樣不捕獲分組的內容,也不分配組號;如:
/hello\s(?!world)/.exec("asdadasd hello world asdasd") //null
 world改變一下:
/hello\s(?!world)/.exec("asdadasd hello wosrlds asdasd") //["hello "]
  • "(?<!exp)" 匹配前面不是exp的位置;如:
/(?!<\d)123/.exec("abc123 ") // ["123"]

4、Javascript中正則表達式的使用

在JavaScript中定義一個正則表達式語法爲:

var reg=/hello/    或者  var reg=new RegExp("hello")

接着列舉一下JavaScript中可使用正則表達式的函數,並簡單介紹一下這些函數的做用。

4.1 String.prototype.search方法

用來找出原字符串中某個子字符串首次出現的索引index,沒有則返回-1。能夠在官方文檔中瞭解更多。

"abchello".search(/hello/);  //  3

4.2 String.prototype.replace方法

用來替換字符串中的子串。簡單例子:

"abchello".replace(/hello/,"hi");   //  "abchi"

官方文檔中有提到:

若是第一個參數是 RegExp對象,那麼替換字符串能夠插入特殊變量名$n,n是個小於100的非負整數,表示插入第 n 個括號匹配的字符串。

因此我在文中一開始提到的需求就能夠用
str.replace(/<span>(.*?)<\/span>/g, '<img src="$1"/>') [$1表示/(.?)</span>/g中的「(.?)」)匹配的字符串]
答案來解答。

4.3 String.prototype.split方法

用來分割字符串

"abchelloasdasdhelloasd".split(/hello/);  //["abc", "asdasd", "asd"]

4.4 String.prototype.match方法

用來捕獲字符串中的子字符串到一個數組中。默認狀況下只捕獲一個結果到數組中,正則表達式有」全局捕獲「的屬性時(定義正則表達式的時候添加參數g),會捕獲全部結果到數組中。

"abchelloasdasdhelloasd".match(/hello/);  //["hello"]
"abchelloasdasdhelloasd".match(/hello/g);  //["hello","hello"]

4.5 RegExp.prototype.exec方法

和字符串的match方法相似,這個方法也是從字符串中捕獲知足條件的字符串到數組中,可是也有兩個區別。
一、exec方法一次只能捕獲一份子字符串到數組中,不管正則表達式是否有全局屬性

/hello/g.exec("abchelloasdasdhelloasd"); // ["hello"]

二、正則表達式對象(也就是JavaScript中的RegExp對象)有一個lastIndex屬性,用來表示下一次從哪一個位置開始捕獲,每一次執行exec方法後,lastIndex就會日後推,直到找不到匹配的字符返回null,而後又從頭開始捕獲。 這個屬性能夠用來遍歷捕獲字符串中的子串。

var reg=/hello/g;
reg.lastIndex; //0
reg.exec("abchelloasdasdhelloasd"); // ["hello"]
reg.lastIndex; //8
reg.exec("abchelloasdasdhelloasd"); // ["hello"]
reg.lastIndex; //19
reg.exec("abchelloasdasdhelloasd"); // null
reg.lastIndex; //0

4.6 RegExp.prototype.test方法

用來測試字符串中是否含有子字符串

/hello/.test("abchello");  // true

5、總結

總算是對正則表達式瞭解了一些,要熟練掌握還需後面多多實踐^_^
參考資料:
1.http://www.cnblogs.com/zery/p/3438845.html
2.http://www.cnblogs.com/tzyy/p/4927476.html
3.http://www.codeyyy.com/regex/index.html

相關文章
相關標籤/搜索