【JavaScript 筆記】正規表達式

Chengcheng Hsu
10 min readFeb 15, 2022

--

此文為 Regular Expressions For Regular Folk《簡易 Regular Expression 入門指南》《[Javascript] 初探Regex 正規表達式》《十五分鐘認識正規表達式,解決所有文字難題》的學習筆記,以下有些例子如有雷同,純屬我把裡面例子放過來而已、但是我想以更囉嗦的方式來解釋每個符號的意思,話不多說直接開始。

🎯 正規表達式是什麼

直接來看一下 Regular Expressions For Regular Folk 怎麼定義

A regular expression is a sequence of characters that define a search pattern.

正規表達式是用一串符號來定義我們要搜尋的模式。

像是這樣 /^.+@(.+)\./i,一串完全不曉得在幹嘛的符號就是正規表達式,裡面的符號是由你自己定義的,視你要處理的問題來定義,簡單來說這一串符號可以協助你去找你手上的資料是不是符合你定義的搜尋模式,並採取你想要處理的動作。

🎯 可以應用的地方

  1. 用來尋找匹配到的字串
  2. 用來取代匹配到的字串
  3. 用來驗證使用者輸入資料欄位
  4. 用來擷取某段想要的資訊,甚至加以利用

例如:

  • 當你打 API 回來的資料需要做處理後再放在前端頁面上
  • 當你今天要驗證使用者輸入的使用者名稱和密碼是否符合你設定的條件,如 Google 建立帳戶頁面會要求使用者名稱是否使用英文,數字和半形句號,密碼是否使用 8 個字元以上的英文字母、數字和符號

🎯 如何宣告正規表達式

  • 第一種:寫在兩個正的斜線裡面,將正規表達式放在//裡面,宣告後就會是一正規表達式的物件。
  • 第二種:用 new RegExp 並將正規表達式放在''裡面,只是要特別注意若使用到\時,要把 \ 改成 \\,不然的話會被當作跳脫字元來看待(note:跳脫字元 Escaping characters,意思是我們需要確保它們被辨識為文字,而非程式碼本身。),也就是第一個 \ 代表跳脫字元,為了確保第二個 \ 還存在,第二個 \是正規表達式的寫法。
var re = /這裡面放正規表達式/flag
// flag 參數為 optional
var re = new RegExp('這裡面放正規表達式', 'flag')
// flag 參數為 optional
===========================================================
※flag:
g:全域比對(Global match)
i:忽略大小寫(Ignore case)
gi:全域比對並忽略大小寫
===========================================================var re = new RegExp('^09\d{8}$') // => /^09d{8}$/,會被當作跳脫字元
var re = new RegExp('^09\\d{8}$') // => /^09\d{8}$/,不會被當作跳脫字元

🎯 如何匹配

  1. test :比對字串是否符合 pattern,成功失敗會回傳 boolean
  2. exec :比對會成功會獲得詳細資訊,比對失敗則會回傳 null
const re = /^09(\d{8})$/console.log(re.test(你要測試的字串))console.log(re.test("0911222333")) 
// true
console.log(re.exec('0911222333'))
//['0911222333','11222333',index: 0,input: '0911222333', groups: undefined]
console.log(re.exec('Hello World !!'))
// null

若是要找到配對的字可以用:

  1. match:找出第一個比對成功的詳細資訊,加上 g flag 則會列出所有比對成功的字串
  2. matchAll:成功匹配後會返回一個 Iterator,可以用 for...of 或者是用 [...] 去把值取出
const re = /a.c/gconsole.log("abcadc".match(re))//['abc', 'adc']console.log(..."abcadc".matchAll(re))//['abc', index: 0, input: 'abcadc', groups: undefined ] [ 'adc', index: 3, input: 'abcadc', groups: undefined ]

🎯 如何練習

為了快速知道正規表達式寫法是否正確,可以用 regex101 來練習,把你定義的正規表達式寫在上面,下面放上想測試的字串,反藍代表有比對到你的正規表達式所設定的條件,右方有 explanation 直接偵測你寫的條件是什麼,如果有寫錯就會反紅。

代表我要比對有任何 abc 的字串

🎯 所以我說那些符號呢

⭐ 集合

[]代表只要符合 [] 裡面任一個字就是符合,[^] 則相反過來的意思

1. /[0123456789]/ :代表我要比對有包含數字的字串,可以簡化成/[0-9]/
2. /[abcdefghijklmnopqrstuvwxyz]/ :代表我要比對有包含小寫字母的字串,可以簡化成 /[a-z]/
3. /[^a-z]/:代表不比對到有包含小寫字母的字串
不比對到有包含小寫字母的字串

⭐ 特殊字元

\ :代表只要符合跳脫字元 \和特定字元的定義就是匹配,如 \d \w 等等,主要是為了更簡潔的表達要搜尋的條件,跳脫字元 \ 是要來告知後面的特定字元不是一個直接匹配的字元,如前面所述,如果你用 new RegExp 宣告就須注意是否要多加一個 \

^:代表字串開頭的意思,因為正規表達式所配對的是「部分」的字,因此可以用此方式去限制開頭

$:代表字串結尾的意思,因為正規表達式所配對的是「部分」的字,因此可以用此方式去限制結尾

.:代表「任意字元」,可以比對到任何一個字,數字、字母以及符號等等。

1. /\d/ :代表只有數字就符合,其實就是 /[0-9]/
2. /\w/:代表比對數字、英文大小寫字母還有底線,換句話說等於 /[a-zA-Z0-9_]/
3. /\s/:代表可以配對到任何空白(空白字元、tab 以及換行)
4. /^09\d\d\d\d\d\d\d\d$/:代表以 09 開頭後面接八個數字就符合,也就是檢查電話號碼
5. abc...:代表 abc 後面接三個任一字元就符合
abc 後面接三個任一字元,並且接一個大小寫字母、數字底線、再接二個數字就符合

更多特殊字元的定義:連結

⭐ 量詞

{}:代表你可去設定重複的東西幾次

?:量詞的特殊字元,代表出現 0 或 1 次,等同 {0,1}

*:量詞的特殊字元,代表出現 0 次或以上,等同於 {0,}

+:量詞的特殊字元,代表出現 1 次或以上,等同 {1,}

1. 原本檢查電話號碼會是 /^09\d\d\d\d\d\d\d\d$/ ,中間就可以用 /^09\d{8}$/ 來代替。
3. /\d{5,10}/ :代表 5 至 10 的數字就符合
4. /\d{5,}/ :代表至少 5 個數字就符合
5. /\d{,3}/ :代表至多 3 個數字就符合
6. /\d+/ :代表一個或以上個數字就符合

不過在量詞的使用有一點要注意,就是像\d{2,}+?*這些預設屬於 Greedy 貪婪量詞,也就是會以連續出現次數 越多 為優先匹配,因此如果我們在後面加上一個問號如 \d{2,}?+???*? 就變成 Lazy 惰性量詞,意思是以連續出現次數 越少 為優先匹配。

這段是由《十五分鐘認識正規表達式,解決所有文字難題》改寫的,因為這段寫得很好,所以拿過來放,其他更多解釋可參考贪婪量词和惰性量词

例如:

會匹配到至少 3 個數字以上,最多的數字 123456
加上問號後,會匹配到至少 3 個數字以上,最少的數字 123

⭐ 群組

():Capturing Groups,代表捕獲你匹配到的東西,並加以利用

例如可以取出身分證字號第二個字元來判斷男女,return 時就會const re = /F(\d{1})(\d{8})/console.log(re.exec("F223456789"))
// [
'F223456789',
'2', // 你捕獲的東西
'23456789', // 你捕獲的東西
index: 0,
input: 'F223456789',
groups: undefined
]

⭐ 環顧

概念是你設定一個 A 字元,當然這裡的 A 代表任何你想設定的東西,而它就是一個定位,向 A 的前面看或後面看,符合你設定的條件 B 即代表匹配,因此區分為 (Lookahead 向前環顧)向前環顧,和 (Lookbehind 向後環顧也就是向後看,其各自又有 positive 與 negative 兩種判斷方式

A(?=B):代表 A 後方的條件要符合 B 才會匹配到 (Positive Lookahead)

A(?!B) :代表 A 後方的條件不符合 B 才會匹配到 (Negative Lookahead)

(?<=B)A:代表 A 前方的條件要符合 B 才會匹配到(Positive Lookbehind)

(?<!B)A:代表 A 前方的條件要不符合 B 才會匹配到(Negative Lookbehind)

代表 B 後面接 C,這個 B 才匹配,前面的 B 後面是 A 不匹配
A 前面的不是 B 才匹配

🎯 今晚我想來個例子

驗證密碼總會有幾個條件

1. 請混合使用大小寫字母以及數字的組合,並且至少 6 個字元
2. 至少一個數字
3. 至少要有 1 個大寫字母
4. 至少要有 1 個小寫字母
  1. 先設定須由大小寫字母數字來組合,並且至少 6 個字元
第一行字串沒有 6 個字元因此不匹配

2. 設定必須有數字的向前環顧,(?=)前面沒有設置條件代表會去看所有間隔後的意思,裡面的條件是表示 . 任意字元出現 0 次或以上並接一數字即符合

第二行字串沒有數字因此不匹配

3. 設定必須有大小寫字母的向前環顧

第三行字串沒有大寫字母因此不匹配,只有第四行匹配

🎯 總結

一開始學正規表達式我也看傻了,到底這個那個符號是代表的是什麼意思,為什麼湊在一起又不是我想的條件,甚至我寫完這篇後可能還是有很多題目是寫不出來的,但只要自己慢慢練習就能慢慢掌握,從最小的符號單位開始熟悉,到後來就會了解每個區塊的意思,慢慢來總是比較快的,期許大家都能把正規表達式越寫越順。

參考文章:

  1. Regular Expressions For Regular Folk
  2. 簡易 Regular Expression 入門指南
  3. [Javascript] 初探Regex 正規表達式
  4. 十五分鐘認識正規表達式,解決所有文字難題
  5. [JavaScript] 來寫正規表達式 Regex
  6. Regex 正規表示法 — 群組與環顧 (Groups & Lookaround)

--

--

Chengcheng Hsu

Frontend developer | 醉心於程式與文學,學習與反饋於現實生活 | Quality over time spent | Slowly but surely | contact me: ychsu.wk@gmail.com