最近在從新學習正則表達式,把在學習過程當中所遇到的案例,還有比較難理解概念用本身的理解分析並整理總結。git
若有哪些地方不對,歡迎指正,謝謝!(๑•ᴗ•๑)github
本系列使用的JavaScript
所支持的正則表達式語法,並推薦你使用 regexr.com/ 去作相應的練習。正則表達式
假定你已經熟悉元字符
,方括號
,修飾符
,量詞
及RegExp對象
。bash
若是沒有,請先看一遍文檔
www.w3school.com.cn/jsref/jsref…post
本系列同步GitHub github.com/Janking/Blo…學習
在上一篇介紹千分位的時候,就有用到重複分組,這是一個很容易理解錯誤的點,至少我開始的時候是理解錯誤的。code
假定用這個正則去匹配 1234567890
,開始我覺得分組小括號(\d\d\d)
的最終結果是 123
,456
,789
都能拿到,但結果卻只有789
regexp
重複分組的匹配在每次引擎退出該分組的時候被捕獲,並會覆蓋該分組在以前匹配的任何文本cdn
模擬一下引擎工做的步驟:
1. 第一次匹配,捕獲到 `123`,退出分組
2. 第二次匹配,捕獲到 `456`, 覆蓋上一次捕獲的`123`,退出分組
3. 第三次匹配,捕獲到 `789`,覆蓋上一次捕獲的`456`,退出分組
4. 退出重複分組,結束複製代碼
由於重複分組最後一次循環存儲的是789,另外兩次分組匹配,也就是123,456是沒法被獲取的。
若是想要得到全部結果,就要把重複匹配放進分組中 /((\d\d\d){3})/
<p>...</p>
中的內容/<p>(.*?)<\/p>/g.exec('<p>Hello,<em>world</em></p><p>Hello,Janking</p>')
[
"<p>Hello,<em>world</em></p>",
"Hello,<em>world</em>",
index: 0,
input: "<p>Hello,<em>world</em></p><p>Hello,Janking</p>"
]複製代碼
假如沒有?
,而匹配結果就會差很遠,不信你看!
/<p>(.*)<\/p>/g.exec('<p>Hello,<em>world</em></p><p>Hello,Janking</p>')
[
"<p>Hello,<em>world</em></p><p>Hello,Janking</p>",
"Hello,<em>world</em></p><p>Hello,Janking",
index: 0,
input: "<p>Hello,<em>world</em></p><p>Hello,Janking</p>"
]複製代碼
缺乏了問號?
,結果把中間的</p><p>
也匹配進來了,爲何一個字符不一樣,匹配結果就差別那麼大?這裏涉及到正則表達式中比較重要的概念:貪婪匹配,懶惰匹配,回溯
屬於貪婪模式的量詞,也叫作匹配優先量詞,包括:{m,n}
,{m,}
,?
,*
和 +
。
在匹配優先量詞後加上?
,即變成屬於惰性匹配的量詞,也叫作忽略優先量詞,包括:{m,n}?
,{m,}?
,??
,*?
和 +?
。
當前前面分支/重複匹配成功後,沒有多餘的文本可被正則後半部分匹配時,會產生回溯
用一個簡單的例子來解釋一下貪婪匹配和惰性匹配!
貪婪 : /\d+\b/
惰性 : /d+?\b/
文本 : 1234a
貪婪正則匹配 1234a
時的過程是這樣的:
1. \d+ 匹配獲得 1234
2. \b 卻匹配失敗,由於它的左邊必須是數字,而不是字母 (\b 是分詞邊界匹配,用來獲取位置,而不是文本,上一節有講到)
4. 這個時候,\d+會嘗試回吐一個字符,即匹配結果爲 123 ,可\b仍是匹配失敗!
5. 那就繼續回吐,一直到 1,仍是匹配失敗,那麼這個正則就總體匹配失敗了
6. 這個回吐匹配結果的過程就是回溯複製代碼
惰性正則匹配 1234a
時的過程是這樣的:
1. \d+? 首先匹配,結果是 1 ,緊接着 \b 匹配失敗
2. 那就 \d+? 繼續匹配,結果是 12 ,緊接着 \b 仍是匹配失敗
3. \d+? 一直匹配到1234,緊接着的 \b 依然匹配失敗
4. 結果整個正則匹配不成功複製代碼
經過這兩個例子的比較,相信你會猜到回溯會影響匹配速度,回溯的過程慢那是相對那些DFA引擎。
而JS的正則引擎是NFA(非肯定型有限自動機),匹配慢,編譯快。
本章節將的案例只有兩個,主要是涉及到幾個重要概念,佔了必定的篇幅,因爲本人不喜歡把文章寫的太長,影響閱讀體驗,因此就此打住,從下一篇開始會重點的去分析經常使用正則表達式的匹配過程,敬請期待。