《前端竹節》(2)【正規表示式】

sept08發表於2018-04-17

正規表示式在前端開發中,對於字串處理任務來說,絕對是一件可以祭出的大殺器。同時對於前端開發人員來說也是一項基本技能,但若只是停留在能看懂,知道去哪查的階段,那距離得心應手地運用差的可能不止一步兩步。

行業總習慣通過工作年限,來粗略估計一個工程師的能力與水平,因為隨著時間的延展總覺得會積累下些許經驗。但年限這種間接的衡量指標太因人而異,太難得到及時的正反饋。後來慢慢地發現,只有基於自己獨立地思考,總結並輸出才會感到真實的成長,就像竹子長一段就得生一個節。

一. 正則使用分類

正規表示式(後文簡稱為“正則”)可劃分出兩種使用方式:

通過正則字面量與通過RegExp建構函式建立出來的正則物件,在不考慮訪問正則物件屬性的情況下,是等價的。如果需訪問正則物件的屬性,需通過RegExp初始化正則例項。

  1. 正規表示式字面量 /正則匹配模式/[修飾符]
    字串物件內建了一些與使用正規表示式相關的方法,這些方法的入參就是所需的正規表示式字面量

    • match返回一個陣列或者在未匹配到時返回null
    • search返回匹配到的位置索引,或者在失敗時返回-1
    • replace使用替換字串替換掉匹配到的子字串
    • split一個使用正規表示式或者一個固定字串分隔一個字串,並將分隔後的子字串儲存到陣列中
  2. RegExp構造的正規表示式物件 new RegExp("正則匹配模式"[, 修飾符])
    通過正則建構函式例項化的正則物件,同樣也具有類似的方法

    • exec返回一個陣列或者在未匹配到時返回null
    • test匹配到返回true否則false

二. 正則的使用(持續更新)

  1. 當匹配到時,execmatch返回結果的不同

    • 字串的match方法,當正規表示式按照字面量傳參時,返回匹配到字串的陣列

      // 字串的match方法
      var str = "cdbbdbsbz"
      var ret1 = str.match(/d(b+)d/g)
      console.log(ret1) // ["dbbd"]

      當傳參為正則物件時,返回值與exec方法相同。

    • 正則物件的exec方法,返回從索引值處開始首次匹配到結果的字串陣列,陣列的第一個元素為結果字串,若匹配模式中存在括號,則括號中的子模式在本次匹配中得到的字串,依次排列在結果陣列中。與此同時,該陣列物件還附帶了一些相關的屬性。

      // 正則物件的exec方法
      var regExp = new RegExp(/d(b+)d/, `g`)
      var ret2 = regExp.exec(str)
      console.log(ret2) // ["dbbd", "bb", index: 1, input: "cdbbdbsbz", groups: undefined]
      物件 屬性 描述 例子中對應的值
      retArray 匹配到的字串,和所有被記住的字串 [“dbbd”, “bb”]
      index 本次匹配結果,開始的索引值 1
      input 初始字串 “cdbbdbsbz”
      [0] 本次匹配到的字串 “dbbd”
      regExp lastIndex 下一個匹配的索引值 5
      source 匹配模式的文字 “d(b+)d”
  2. 使用括號的子字串匹配(組匹配)
    拿上例的匹配模式來看/d(b+)d/g,括號中匹配到的子字串,會被記錄在陣列元素[1],…,[n]中,且儲存數量可以是無限的。除了通過js直接使用外,還可以這樣使用:

    var name = "John Tom"
    var newName = name.replace(/(w+)s(w+)/, "$2 $1")
    console.log(newName) // Tom John
  3. 正規表示式修飾符

    • g:全域性搜尋
    • i:不區分大小寫搜尋
    • m:多行搜尋,^$匹配的開始或結束輸入字串中的每一行,而非整個輸入字串
    • u:開啟Unicode模式,用來正確處理大於uFFFF的字元
    • y:粘連匹配,類似全域性搜尋,但不同是其要求在lastIndex的位置發現匹配,而g是從lastIndex處開始搜尋,也就是說粘連匹配y模式中隱藏了頭部匹配的標誌^
  4. 具名組匹配
    上面有討論過組匹配的概念和用法,通過陣列下標的方式使用總會帶來些許不便,所以在ES2018中引入了具名組匹配,允許為每一個組匹配指定一個名字,以方便閱讀和呼叫,來看例子:

    // 之前的組匹配
    const RE_DATE = /(d{4})-(d{2})-(d{2})/;
    const matchObj = RE_DATE.exec(`1999-12-31`);
    const year = matchObj[1]; // 1999
    const month = matchObj[2]; // 12
    const day = matchObj[3]; // 31
    // 使用具名組匹配
    const RE_DATE = /(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/;
    const matchObj = RE_DATE.exec(`1999-12-31`);
    const year = matchObj.groups.year; // 1999
    const month = matchObj.groups.month; // 12
    const day = matchObj.groups.day; // 31

三. 正則匹配模式

下表列出了在正規表示式中,可以利用的特殊字元的完整列表和描述

字元 含義
/ 1. 在非特殊字元前,表示特殊用途; 2. 在特殊字元前,轉義為字面量;3. 在new RegExp(“pattern”) 中需將 進行轉義。
^ 匹配輸入的開始。若設定多行匹配,則也匹配換行符後緊跟的位置
$ 匹配輸入的結束。若設定多行匹配,則也匹配換行符前的位置。
* 匹配前一個表示式0次或多次。等價於 {0,}
+ 匹配前面一個表示式1次或者多次。等價於 {1,}
? 1. 匹配前面一個表示式0次或者1次。等價於 {0,1};2. 如果緊跟在任何量詞 *、 +、? 或 {} 的後面,將會使量詞變為非貪婪的(匹配儘量少的字元),和預設使用的貪婪模式(匹配儘可能多的字元)正好相反。
. 匹配除換行符之外的任何單個字元
(x) 匹配 x 並且記住匹配項
(?:x) 匹配 x 但是不記住匹配項(非捕獲括號)
x(?=y) 匹配 x 僅僅當x後面跟著y (正向肯定查詢)
x(?!y) 匹配 x 僅僅當x後面不跟著y(正向否定查詢)
{n} 匹配了前面一個字元剛好發生了n次(n為正整數)
{n,m} 匹配前面的字元至少n次,最多m次
[xyz] 表示字符集合,匹配方括號的中任意字元
[^xyz] 表示一個反向字符集,匹配沒在方括號的中任意字元
[] 匹配一個退格(U+0008)
匹配一個詞的邊界
B 匹配一個非單詞邊界
cX 當X是處於A到Z之間的字元的時候,匹配字串中的一個控制符
d 匹配一個數字,等價於[0-9]
D 匹配一個非數字字元,等價於[^0-9]
f 匹配一個換頁符

匹配一個換行符

匹配一個回車符
s 匹配一個空白字元,包括空格、製表符、換頁符和換行符
S 匹配一個非空白字元
匹配一個水平製表符
v 匹配一個垂直製表符
w 匹配一個單字字元(字母、數字或者下劃線)
W 匹配一個非單字字元

它返回最後的第n個子捕獲匹配的子字串(捕獲的數目以左括號計數)

相關文章