正則表達式案例分析 (二)

前言

最近在從新學習正則表達式,把在學習過程當中所遇到的案例,還有比較難理解概念用本身的理解分析並整理總結。git

若有哪些地方不對,歡迎指正,謝謝!(๑•ᴗ•๑)github

本系列使用的JavaScript所支持的正則表達式語法,並推薦你使用 regexr.com/ 去作相應的練習。正則表達式

假定你已經熟悉元字符方括號修飾符,量詞RegExp對象bash

若是沒有,請先看一遍文檔
www.w3school.com.cn/jsref/jsref…post

本系列同步GitHub github.com/Janking/Blo…學習

系列目錄

正則表達式案例分析 (一)spa

案例分析

(1) 重複分組

在上一篇介紹千分位的時候,就有用到重複分組,這是一個很容易理解錯誤的點,至少我開始的時候是理解錯誤的。code

https://user-gold-cdn.xitu.io/2017/7/23/0752787423b4fe0c5aaa52f2126294ba
https://user-gold-cdn.xitu.io/2017/7/23/0752787423b4fe0c5aaa52f2126294ba

假定用這個正則去匹配 1234567890,開始我覺得分組小括號(\d\d\d)的最終結果是 123456789都能拿到,但結果卻只有789regexp

重複分組的匹配在每次引擎退出該分組的時候被捕獲,並會覆蓋該分組在以前匹配的任何文本cdn

模擬一下引擎工做的步驟:

1. 第一次匹配,捕獲到 `123`,退出分組
2. 第二次匹配,捕獲到 `456`, 覆蓋上一次捕獲的`123`,退出分組
3. 第三次匹配,捕獲到 `789`,覆蓋上一次捕獲的`456`,退出分組
4. 退出重複分組,結束複製代碼

由於重複分組最後一次循環存儲的是789,另外兩次分組匹配,也就是123,456是沒法被獲取的。

若是想要得到全部結果,就要把重複匹配放進分組中 /((\d\d\d){3})/

(2) 獲取<p>...</p>中的內容

https://user-gold-cdn.xitu.io/2017/7/23/92b63477e6366c36f7dac825f3bda438
https://user-gold-cdn.xitu.io/2017/7/23/92b63477e6366c36f7dac825f3bda438

/<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(非肯定型有限自動機),匹配慢,編譯快。

結束語

本章節將的案例只有兩個,主要是涉及到幾個重要概念,佔了必定的篇幅,因爲本人不喜歡把文章寫的太長,影響閱讀體驗,因此就此打住,從下一篇開始會重點的去分析經常使用正則表達式的匹配過程,敬請期待。

參考文獻:

  • 《精通正則表達式》
  • 《正則表達式經典實例》
相關文章
相關標籤/搜索