『再也不迷茫 - 正則表達式』JS正則要點梳理 持續更新

[TOC]html

寫在前面 - Lionad

正在看VueJS的源碼, 看到了HtmlParser部分, 感受之前看的正則表達式基礎知識已經徹底不夠用了, 現翻閱博客資料, 將一些JS中正則表達式難用的部分總結概括, 方便本身和sf友翻閱.前端

正則分組

重複匹配

對於重複的匹配, 咱們常用到正則表達式的分組功能, 咱們使用正則匹配IP地址來實踐一下.正則表達式

假設咱們要匹配的IP地址在區間 0.0.0.0 - 255.255.255.255 之間, 能夠直觀的瞭解到, 咱們只須要匹配 三位數字+點號 三遍, 再匹配三位數字一遍就能夠了. segmentfault

這裏說的 三位數字+點號 既是咱們說的一種規則, 咱們能夠在表達式中將它們轉化爲規則即: \d{1,3}\., 當咱們把規則用括號包裝後, 就變成了組: (\d{1,3}\.), 因此匹配IP地址的正則表達式能夠寫做: (\d{1,3}\.){3}\d{1,3}ui

換種思路, 咱們也能夠這樣匹配: \d{1,3}(\.\d{1,3}){3}code

拓展: 聰明的你可能已經想到, \d{1,3} 匹配是有疏漏的. 在實際生產過程當中, \d{1,3} 可能匹配 999 這種數字, 他是一個錯誤的IP地址段. 這裏貼上真實的IP地址正則匹配供你們參考: ((25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))) , 另人愉快的是, 它使用的分組策略仍然是不變的.

後向引用(反向引用)

咱們考慮一個很特殊的狀況, 當咱們要匹配四個IP段相同的狀況, 如 100.100.100.100 時, 重複匹配分組的策略失效了: 重複匹配分組 並不能保證匹配相同的數字 -> 這時候咱們須要藉助 後向引用 策略的力量了(少年, 你渴望力量嗎2333, 戳我頭像, 帶你探索音樂與代碼交織的文藝道路.)htm

後向引用在不一樣語言的正則表達式書寫中, 有不一樣的語法, 咱們討論JS中最多見的一種, 形如: \number 的後向引用, 其中, number 表明分組的序號.blog

給你一個簡單的栗子, 瞬間就記住了, 假使咱們要匹配重複的三位數字, 咱們將匹配一個數字的規則標記爲一個分組: (\d), 重複匹配這個分組(第一個分組)的具體內容三次: (\d)\1, 這樣就達到了目的.索引

咱們很容易將重複匹配和後向引用分別開來: 前者是重複匹配相同的規則, 後者是匹配分組的具體內容.字符串

默認的一些規則須要稍加理解並記住:

  • \0表明的是, 整個正則表達式的匹配的內容

捕獲分組與不捕獲分組

當咱們用括號包裝一個規則, 即造了一個分組, 這個分組是默認被捕獲的, 也就是說, 咱們能利用後向引用等手段(\number)去調用這個分組.

可是若是咱們不想保存這個分組的結果到索引中, 即可以使用形如(?:)的不捕獲分組, 表示不須要暫存此分組.

正則斷言

還記得我看過的一篇大概名爲<30分鐘學會正則表達式>的文章中, 裏面說起過正則斷言.
當時感受真是一看就懂. 但很遺憾, 實際生產中, 使用各類複雜正則表達式的狀況實在是太少, 今天若是不翻閱百度, 我恐怕是不能記起斷言的分類和各類使用方法了.

斷言的字面意思即是, 判定(程序)運行到此時(結果)是這樣的"場景", 它描述的是一種 場景, 換句話說, 是一種"確定的場景". 但要記住的是, 咱們的"結果"是不包含在"場景"裏面的.

VueJS裏頭須要匹配HTML tag, 咱們就以匹配: '<segment>Not Fault</segment>' 中的 'Not Fault' 爲例吧.

咱們若是使用普通的正則表達式, 如 /<segment>.*</segment>/ 會匹配到整個字符串 '<segment>Not Fault</segment>'. 咱們使用斷言, 以"場景"的方式思考: '<segment>' 和 '</segment>' 是一種"確定的場景", 咱們須要匹配的結果是: 'Not Fault', 不管tag內部的字符不管如何變化, tag頭和tag尾都是不變的.

一氣呵成, 咱們繼續往下

先行斷言

先行斷言, 我是這樣理解的: 先匹配內容, 再作"場景"假設.

放到咱們先前的栗子中, 便這樣匹配, 一直匹配內容, 直到碰上 '</segment>' 的場景, 語法以下: (?=</segment>)

後發斷言

後發斷言, 個人理解是: 先匹配場景, 再匹配內容.

放到咱們先前的栗子中, 先匹配 '<segment>' 的場景, 再繼續往下匹配內容, 語法以下: (?<=<segment>)

實踐

正則表達式是對字符串內容作匹配, 因此我將"先"和"後"的理解綁定到內容匹配的前後順序上, 方便理解.

咱們將先行斷言和後發斷言結合起來, 整個表達式以下: (?<=<segment>).*(?=</segment>), 咱們即可得到想要的結果: 'Not Fault' 了.

"正負"斷言

其實咱們剛纔作的是確定的場景, 實際狀況中還有"不知足此場景"的使用場景.

好比, 咱們剛纔使用的表達式: (?<=<segment>).*(?=</segment>) 是確定有 '<segment>' '</segment>' 的場景下去匹配內容, 實際上是使用的 "正後發斷言" 和 "正先行斷言", "正"即表明確定的狀態.

那負斷言, 也就是不知足場景的斷言咯... 語法即把正斷言中的等於號換成感嘆號:

  • 負先行斷言 (?!)
  • 負後發斷言 (?<!)

如: ['1999','2099','2199'...'9099'] 中若是咱們要匹配除了'1999'之外的全部帶有'99'結尾的年份, 咱們可使用表達式: (?<!19)99

拓展: JS中是不支持後發斷言的, 因此嘛... 沒什麼因此, 由於至少還沒碰到過缺乏後發斷言就解決不了的問題2333

後記

網易雲 Lionad_Guirotar : 前端新手一枚, 歡迎各位 加油&吐槽. 戳我頭像, 帶你探索音樂與代碼交織的文藝道路.

參考文章&相關閱讀

相關文章
相關標籤/搜索