正則表達式(************************)


最近在研讀一本巨著《JavaScript忍者秘籍》,里面有一篇涉及到了正則表達式。

我在以前也曾經寫過一篇正則表達式相關的文章《JavaScript與PHP中正則》,這次再做些補充。

書中的源碼可以在此下載。我將源碼放到了線上,如果不想下載,可以直接訪問在線網址,修改頁面名就能訪問到相應示例代碼。

 

一、術語與操作符

1)精確匹配

如果一個字符不是特殊字符或操作符,則表示該字符必須在表達式中出現。

例如“/test/”,就表示“t”后面跟着“e”,“e”后面跟着“s”,“s”后面跟着“t”。

 

2)匹配一類字符

很多時候是想匹配一個有限字符集中的某一個字符。

例如“[abc]”,就是要匹配“a”、“b”或“c”中的任意一個字符。

例如“[^abc]”,就是除了“a”、“b”、“c”之外的任意字符。

例如“[a-m]”,就是從“a”到“m”之間的任意字符。

 

3)轉義

並不是所有字符和其字符字面量都是等價的。

例如匹配“$”、“.”這種特殊字符,需要添加“\”反斜杠,“\$”、“\.”。

 

4)匹配開始與匹配結束

經常需要確保模式匹配一個字符串的開始,或者一個字符串的結束。

/^test/”表示以“test”開始,“/test$/”表示以“test”結尾。

 

5)重復出現

1. “”表示出現一次或不出現,例如“/t?est/”可以匹配“test”或“est”。

2. “+”表示出現一次或多次,例如“/t+est/”可以匹配“test”、“ttest”。

3. “*”表示出現零次或多次,例如“/t*est/”可以匹配“est”、“test”。

4. “{number}”表示指定出現的次數,例如“/a{4}/”可以匹配“aaaa”。

5. “{number,number}”兩個數字表示重復次數區間,例如“/a{1,3}/”可以匹配“aa”、“aaa”或“aaaa”。

6. “{number,}”次數區間的第二個數字可選,表示一個開區間。例如“/a{1,}/”匹配連續2個“a”或更多的“a”。

7. 重復操作默認是貪婪匹配,如果要非貪婪(只做一次匹配)的可以在操作符后面加“”,例如“*?”、“+?”。

 

6)預定義字符類

有一些字符是不可能用字面量字符來表示的(例如回車)。

還有一些經常想匹配的字符類,例如小數位數或一組空白字符。

 

7)分組

如果將操作符應用於一組術語,可以添加小括號。

例如“/(ab)+/”匹配一個或多個“ab”字符串。

當用括號進行分組的時候,就創建了捕獲(capture)。

 

8)或操作符

可以用“|”表示或的關系。

例如“/a|b/”匹配“a”或“b”。

 

9)反向引用

在反斜杠后面加一個要引用的捕獲數量,該數字從1開始,例如“\1”、“\2”。

例如“/<(\w+)>(.+)<\/\1>/”匹配“<b>strong</b>”,不用反向引用是無法做到的。

 

二、匹配捕獲的片段

1)執行簡單的捕獲

從“filter:alpha(opacity=50);”字符串中提取透明度值,可以查看在線結果

復制代碼
function getOpacity(elem) {
  var filter = elem.style.filter;
  return filter ? //#2
    filter.indexOf("opacity=") >= 0 ?
    (parseFloat(filter.match(/opacity=([^)]+)/)[1]) / 100) + "" :
    "" :
    elem.style.opacity;
}

window.onload = function() {
  assert(getOpacity(document.getElementById("opacity")) == "0.5", "The opacity of the element has been obtained.");
};
復制代碼

match返回的第一個索引的值總是該匹配的完整結果,然后是每個后續捕獲結果。

 

2)用全局表達式進行匹配

當應用全局表達式(g),返回值依然是一個數組,匹配所有可能的結果,而不僅僅是第一個匹配結果,在線實例查看

復制代碼
var html = "<div class='test'><b>Hello</b> <i>world!</i></div>";

var results = html.match(/<(\/?)(\w+)([^>]*?)>/); //#1

assert(results[0] == "<div class='test'>", "The entire match.");
assert(results[1] == "", "The (missing) slash.");
assert(results[2] == "div", "The tag name.");
assert(results[3] == " class='test'", "The attributes.");

var all = html.match(/<(\/?)(\w+)([^>]*?)>/g); //#2

assert(all[0] == "<div class='test'>", "Opening div tag.");
assert(all[1] == "<b>", "Opening b tag.");
assert(all[2] == "</b>", "Closing b tag.");
assert(all[3] == "<i>", "Opening i tag.");
assert(all[4] == "</i>", "Closing i tag.");
assert(all[5] == "</div>", "Closing div tag.");
復制代碼

在進行局部匹配時,只有一個實例被匹配了,並且該匹配的捕獲結果也返回了。

在進行全部匹配時,返回的是匹配結果的列表

我們可以用“exec”方法,在全局正則匹配之時,恢復捕獲在線實例查看

復制代碼
var html = "<div class='test'><b>Hello</b> <i>world!</i></div>";
var pattern = /<(\/?)(\w+)([^>]*?)>/g, match;
var num = 0;

while ((match = pattern.exec(html)) !== null) { //#1
  assert(match.length == 4, "Every match finds each tag and 3 captures.");
  num++;
}

assert(num == 6, "3 opening and 3 closing tags found.");
復制代碼

exec方法保存了上次調用的狀態,這樣每個后續調用就可以繼續下去了,直到全局匹配。每一個調用返回的都是下一個匹配及其匹配內容。

match中的內容如下,這里就顯示兩個,其他類似的,下面的index就是當前字符串開始匹配的索引值。

 

3)捕獲的引用

有兩種方法可以引用捕獲到的匹配結果:自身匹配,替換字符串。

1. 自身匹配

復制代碼
var html = "<b class='hello'>Hello</b> <i>world!</i>";

var pattern = /<(\w+)([^>]*)>(.*?)<\/\1>/g; //#1

var match = pattern.exec(html);
console.log(match);

assert(match[0] == "<b class='hello'>Hello</b>",
  "The entire tag, start to finish.");
assert(match[1] == "b", "The tag name.");
assert(match[2] == " class='hello'", "The tag attributes.");
assert(match[3] == "Hello", "The contents of the tag.");

match = pattern.exec(html);
復制代碼

使用了“\1”引用了表達式的第一個捕獲,在本例中該捕獲是標簽名稱,查看在線實例

2.替換字符串

替換字符串“replace”方法,與反向引用不一樣,這里使用“$1”、“$2”語法表示每個捕獲的數字。

assert("fontFamily".replace(/([A-Z])/g, '-$1').toLowerCase() 
    == 'font-family', 'Convert the camelCase into dashed notation');

 

4)沒有捕獲的分組

小括號有雙重責任:分組操作與捕獲。但如果有大量的分組,就會引起不必要的捕獲,查看在線實例

復制代碼
var pattern = /((?:ninja-)+)sword/; //1

var ninjas = "ninja-ninja-sword".match(pattern);

assert(ninjas.length == 2, "Only one capture was returned.");
assert(ninjas[1] == "ninja-ninja-",
  "Matched both words, without any extra capture.");
復制代碼

該表達式只會為外層的括號創建捕獲。


免責聲明!

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



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