Skip to main content

正則表達式 JavaScript RegExp Object

寫搜尋餐廳案例的時候,Su助教提醒了一句不要相信前端輸入值:「直接將前端輸入值進出資料庫,是非常不建議的做法,如果使用者輸入值並非預期或帶有危險性,就容易引發錯誤或資安風險。所以實際上會先做檢查,然後只將需要的值寫入資料庫。」

當下第一個直覺解法是用replaceAll()把一些符號(‘/?”#\@)之類的換成空值再trim()掉,實際開始寫虛擬碼大概3秒就發現我太天真ㄌ這樣要寫好多判斷喔好麻煩(放棄的速度飛快)。

馬上用關鍵字google一下別人都怎麼做,正式進入正則表達式的世界。

Regular Expression

簡單說正則表達式就是建立一個字符串的規則給大家遵守,幫助我們快速找到符合文字設定模式的字串。定義上我覺得 MDN的解說 很平易近人。

立刻也查到很多人直接推薦如何使用正則表達式篩選掉特殊符號的用法,但是尚未完全理解正則表達式的當下是看半天不肯定到底怎麼使用,所以不囉嗦直接進入研究:

創建一條正規表達式

撰寫正規表達式時,有兩種方式:

  1. 使用正規表達式字面值(regular expression literal)
    把你想要的模式用兩個/包起來,直接寫死:

    const regex = /ab+c/
  2. 呼叫 RegExp 物件的建構函式 new RegExp() 來建立一個 RegExp 物件,可以動態產生:

    const regex = new RegExp('ab+c')

    通常都可以在後面再加上 flags 的設定讓選擇更有彈性,這個晚點再說。

使用正則表達式

創建好要比對的模式(pattern)之後,就可以使用它內建的2個方法去做測試,最常用到的就是 RegExp.prototype.test() : .test()會搜尋傳入的字串有沒有符合你設定的pattern,回傳布林值true/false

const regex = /a/
console.log(regex.test('abccc')) // true

正則表達式中的特殊字元

現在我們可以產生自己的正則表達式了,就來認識一下裡面的規則!這裡介紹幾個這次專案有用到以及感覺日後會常用的:

\d 匹配數字 ,通常搭配{匹配次數}
{n} 表示匹配n個字符 重複n次
{n,} 表示至少匹配n個字符 重複n次以上 (至少n次)
{n,m}表示至少n,最多m 重複n到m次
表示匹配字符串的結束位置

默認情況下,匹配必須出現在字符串的末尾,或在字符串末尾的 \n 之前
在多行模式中,必須出現在該行的末尾之前,或在該行末尾的 \n 之前

^ 表示匹配字符串的開始位置

從字符串的開頭開始匹配, 在多行模式中就是從該行的開頭開始
^\d{5,12}$ 保證整個字符串只能是 5–12字的數字
\d{5,12} 保證字符串裡包含5–12個連續的數字,不能保證整個字符串的長度

\b匹配單詞的開頭或結尾,也就是單詞的分界處,僅代表一個位置符號

-代表連續的字符,一種簡易的縮寫方式。數字 1~5,可以寫成 [1–5]
注意連字符的使用一定要搭配方括號,否則會被解讀爲普通字元

\w 匹配英文字母和數字 (字母或數字或下底線),用在/Hi 1.2_3/ 上會返回 H、i、1、2、_、3

\ 把特殊符號轉出來,用 \*表示匹配 * 號,\\匹配 \

"google.tw" 匹配 google.tw
"C:\Windows" 匹配 C:\Windows

+ 表示前面的字符要匹配 1次以上
例如 goo+gle 可以符合 google、gooogle、goooogle...

? 表示匹配前面字符 0次或1次(要嘛有要嘛沒有)

colou?r 可以符合 color 或者 colour...

* 表示匹配 0次以上

0*42 可以符合 42、042、0042、00042...

. 表示匹配除換行符 \\n \\r \\u2028\\u2029 以外的任意單個字符

.* 搭配就是任意個任意字符(但不能是換行)

[^ + 字符組] 反義代碼,匹配"除此之外"的內容。任意字符至少要出現一次

[^aeiou] 匹配除了aeiou這幾個字母以外的任意字符

flags 加上標籤 讓搜尋更完善

正則表達式有可選標籤,允許進行全局和不區分大小寫的搜索。這些標籤可以單獨使用,也可以按任何順序一起使用,並作為正則表達式的一部分,下面列舉兩個常用的:

i 表示比較條件不分大小寫

g 全域搜尋,沒加的話只會返回第一個匹配的內容

flag的用法只要加在最後面就可以了

// 簡單寫法
const regex = /pattern/flags

//建構函式寫法
const regex = new RegExp('pattern', 'flags')

小結

簡單看需要的部分就花了不少時間,回頭檢視自己的程式碼後加入了規範,對應客戶端輸入的keyword來檢查是不是有奇怪的特殊符號:

/[~!@#$%^&*()_+<>?:"{},.\\/;'[\]]/im.test(keyword)

到這裡就大功告成了~

助教看完也給了反向思考:因為只要有一個成立就會丟出錯誤訊息,所以也不用找到全部特殊符號 — 也就是說可以反過來寫成: /[^\w\ \u4E00-\u9FFF]/.text(keyword)

拆開來看就是 [^] + \w + \ + \u4E00-\u9FFF
反查keyword是否有除了英文字母和數字下底線空格中文字以外的字符,讚啊!!

到這裡我的正則表達式筆記量已經爆炸,光整理就耗掉一天,記不住的都靠筆記,有需要再回來查就好了!


參考資料 與 延伸閱讀