JS
Published on

初探 Regex 正規表達式

Authors
  • avatar
    Name
    Mujing
    Twitter

正規表達式英文全名 Regular Expression, 想必一定曾是每個工程師的惡夢,在新手眼裡彷彿精靈語一樣神秘又難親近, Regex 是一把複雜卻威力強大的武器。如果可以活用,在很多場合可以幫助你少寫很多的 if 判斷式,今天這篇文章就要來幫助理解正規表達式。

為什麼需要 Regular Expression?

Regex 可以實用的情境大致有幾種:

  • 尋找匹配的字串
  • 取代匹配的字串
  • 驗證使用者輸入資料欄位
  • 擷取某段想要的資訊

舉例 JS 為例子來說,如果我想要看看資料裡面有沒有某個字元 "M",一個簡單的方式是這樣寫:

    let stringMatch = "This is Mujing.".some(s=>{
        return s=="M"
    }) // Check if there is M in my data.

不過如果今天,當條件變得更多更複雜的時候這時候正規表達式就派上用場了。 (字串裡面必須包含一個數字或一個大寫字母):

let re = ''
let result = 'uSer0910'.match(/([0-9]|[A-Z])/g) //result.length = 1

Regular Expression 規則說明

正規表達式使用時是將規則寫在兩個正的斜線裡面,並且撰寫的時候有幾種類型的匹配方式:

  1. 直接匹配: 例如直接輸入字元 "abc".match(/a/) 就可以匹配到 a 字元。

  2. 使用跳脫字元匹配:有些英文字在 Regex 裡面代表的特殊意義,但因為是用英文字元代表的,所以在使用時要用 \ 跳脫字元來告知這不是一個直接匹配的字元。

  3. 特殊字元匹配:跟第二種相反,有一些特殊符號一但出現,就代表某種意義,如 [] 就代表任意匹配,如果要單純匹配 [ 字元,則必須用反斜線告知。

JS 的 Regular Expression 寫法

JS 裡面寫正規表達式的時候你可以直接用兩個斜線代表,或是 new 一個 RegExp 物件並將要寫的規則寫入建構子,不要用這種做法要注意,RegExp 預設會直接幫你跳脫特殊字元,如果你要在裡面寫跳脫字元規則的話,記得寫兩個反斜線來告訴他不要跳脫:

例如:

new RegExp('d') // return /d/ (變成匹配d這個字元了)
new RegExp('\\d') // return /\d/ (是我要的數字匹配規則)

RegExp 物件底下有一個 test 方法,用法如下:

;/a/.test('An Apple a day.') // return true

就可以很快的測試自己寫的方法對不對了,這個方法用在表單檢查也非常好用。 正規表達式還可以用在很多地方,如 match、split、replace 等操作字串的方法, 學會之後想怎麼用就怎麼用。

以下整理正規表達式常用的特殊規則,或可參考JS 官方文件

跳脫字元規則

這邊有個好記的規則,小寫的

符號說明
\d匹配任意數字
\D匹配任意非數字字元
\w匹配所有文字字元 (a-z、A-Z、0-9、_ )
\W匹配所有“非”文字字元 (標點符號、特殊字元)
\s匹配空白字元
\S匹配“非”空白字元
\b匹配字元邊界 /(空格或開頭/)
\B匹配字元邊界

特殊符號

符號匹配說明
\反斜線,跳脫特殊字元,例如想尋找"/"的時候
.任意字元
$字元結尾
^字元開頭
[]中括號,比對中括號裡面的任一字元,可以用範圍匹配:[A-Z]、[a-z]、[0-9]
[^]^代表「反」,比對中括號裡面"以外"的任一字元
|同程式常見的 OR 邏輯
()群組

指定匹配次數

因為一個字元只會匹配一次,如果要多次匹配,就可以用指定字數的規則。

需注意:這些次數針對的是的是該該符號擺放位置的前一個匹配規則。

符號匹配次數
*0 次或更多
+1 次或更多
?0 次或 1 次
{m}m 次
{n,}最少 n 次
{m,n}從 m 次到 n 次
{m,n}?從 m 次到 n 次,選到匹配最少次的

基礎範例

其實懂了基本邏輯之後,剩下的就是組合而已,匹配的規則要用在查就可以了,因為比較常用的寫法都差不多。

1.驗證手機號碼

手機號碼有 10 個數字,要怎麼寫呢?你可能第一個會想到[0-9],方向對了, 但[0-9]只會匹配一次,如果要匹配 10 次可以這麼寫:

;/[0-9]{10}/

2.商品型號

一般電商在後台上架商品的時候,一個常見的需求是輸入商品型號,為了減少使用者錯誤率也為了提高效率,我們可以用正規表達式解決,假設今天商品型號的規則是:

三個英文字母 + “-” + 五個數字 (例如 ABC-90006 )

那麼其實搭配上面講的匹配次數就可以:

;/[A-Z]{3}-[0-9]{5}/

3.驗證密碼(至少包含一個大寫字母以及一個數字)

這個情況想必跟[A-Z]以及[0-9]脫不了關係,但會遇到順序性的問題,直接給[A-Z][0-9]代表的是先一個大寫字母在加上一個數字,不能夠反過來,這時就會需要最少匹配一次的"+"跟最寬容的"*"。

拆解各種情況:

  • [A-Z][0-9] :匹配一個 A-Z 的字母跟一個 0-9 的數字,而且不能顛倒
  • [A-Z]+ :代表匹配大寫字母最少一次
  • [A-Z]* :代表匹配 A-Z 0次或更多(這樣就代表可有可無,不是我們想要的)
  • [A-Z]+[0-9]+ :匹配[A-Z]最少一次之後在匹配 0-9 最少一次(如:AABB909)

看完上面四個範例你應該就會理解剛剛講的順序性是什麼,根據這個條件,可能會有的情況有幾種:

  • [任意字串] + [至少一個 A-Z 字元] + [至少一個數字] + [任意字串]
  • [A-Z 字元在開頭] + [任意字串] + [至少一個數字]

簡單來說就是要考慮我要匹配的字元是在開頭以及結尾,我們可以用 “.*”來達成 [ 任意字符 ]的[ 匹配任意次(包含 0 次)],以及 "+" 達成最少一次的匹配:

  • .*[A-Z]+ :表示至少有一個 A-Z 字元,前面可以有其他「任意次」個「任意字元」。

組合!!

.*[A-Z]+.*[0-9]+.*

這樣就可以達到不管前面有什麼,最後有什麼,只要有一個 A-Z 跟一個數字,就符合規則啦! 但最後還要考慮順序的問題,可以用 OR 邏輯將數字跟字母對調,就完美符合我們的需求啦!

.*[A-Z]+.*[0-9]+.* | .*[0-9]+.*[A-Z]+.*

幾個練習 Regex 的網站

比較推薦第一個,他是互動式的,一步一步帶你了解正規表達式的使用方式,說明的很詳細。 剩下兩個則是自己在測試的時候很好用,寫完表達式右邊還有規則的說明,非常方便。

  1. RegexOne
  2. Regex101
  3. Regexr