正則表達式

不趕快回來填這個坑不行。

一些不錯用的網站

什麼是正則表達式?

正則表達式(RegExp, Regular Expression)就是用來檢查某一個字串是否符合「一個規則」。

我們會用 RegExp 來建立一個規則,利用這個規則就可以對字串做檢測。

建立方式

RegExp 是一個物件,可以用 //new RegExp() 來建立。

檢測方法

test() 檢查參數是否符合正規表達式的規則:

1
2
const regExp = /a/
regExp.test('aabbccss') // ture

上面的規則是「只要有 a 字元」就算通過。

怎麼設定規則

  • ^ 起始字串的規則
  • $ 結尾字串的規則
  • . 「單個」任意字元的規則。除了 \n(換行)跟 \r \u2028 \u2029 這些 不可見字元
  • \ 跳脫字元。把會有衝突的字元當成純字串,例如:/\$100/ /2021\/12\/15/
  • \d 任意數字的規則
  • \D 除了數字以外的規則
  • \w 任意英文、數字、底線的規則
  • \W 除了任意英文、數字、底線以外的規則
  • \s 任意空白字元。包含 \f \n \r \t \v 這些 不可見字元
  • \S 非任意空白字元(同上)的規則
  • | 滿足其中一個條件就 OK 的規則
  • - 自訂範圍的規則。像 1 ~ 5 可以寫成 [1-5];a ~ d 可以寫成 [a-d]
  • [] 包含括弧內文字的規則(出現一個就算符合)。例如:/a[bcd]b/「ab 夾 bcd」都可以。
  • [^] 不包含括弧內文字的規則。例如:/a[^bcd]b/「ab 不夾 bcd」都可以。
  • {n, m} 連續出現次數的規則,n 為下限,m 為上限。重點是「連續」這個功能。
    • /\d{3}/ 代表必須連續出現 3 次以上才可以。
    • {0,3} 代表最少連續 0 次,最多連續 3 次
    • {1,} 代表至少連續 1 次
    • {,3} 代表最多連續 3 次。
  • ? 代表只出現 0 或 1 次的規則,等同於 {0,1}
  • * 代表出現 0 或 多次的規則,等同於 {0,}
  • + 代表至少出現 1 次的規則,等同於 {1,}

補充一下,? * + 都只看他前面那「一個」字元。

不可見字元的補充:

  • \v 垂直製表符,可以想成是 tab 的反方向
  • \r 回車,是「Enter」
  • \v Backspace, 是「倒退鍵」

修飾符(寫在 // 後面)

正確的名稱是「flag(標誌)」,但簡單一點可以想成是「參數」。

  • g 比較所有字串(global),預設是找到第一個符合的對象就停止了(這個粉重要哦,搭 String 方法的時候通常會用到)
  • i 不分大小寫(ignore case)
  • m 區分換行(multi line),會用在要檢查的字尾後面剛好有一個換行符號的情況
1
2
3
4
const regExpA = /y$/
const regExpB = /y$/m
regExpA.test('enjoy\n') // false
regExpB.test('enjoy\n') // true

一些重要的觀念

匹配的是「部分」內容

1
2
const regex = /\d{3,5}/
regex.test('12ab1234567') true

在我練習時,我寫了 /\d{3,5}/,原本以為意思是「最少連續 3 次,最多連續 5 次」,所以想說上面的數字超過 5 次了,應該會得到 false

但是正則表達式匹配的是字串中的「部分」內容,所以上面的字串中可以到匹配的是:

  • 123
  • 1234
  • 12345
  • 234
  • 2345
  • 23456
  • … 以此類推

如果你想正確的使用 {} 的上下限規則,請參考下面的例子。

{n,m} 設定上下限的功能通常是用在「夾在中間」的情形:

1
2
3
4
5
6
// 部分字串中包含「ac ... b」的字串
const regExp = /ac{1,3}b/
regExp.test('acb') // true
regExp.test('accb') // true
regExp.test('acccb') // true
regExp.test('accccb') // false

或者是直接加上 ^ $ 來設定開頭跟結尾條件:

1
2
3
4
5
const regExp = /^\d{1,3}$/
regExp.test('1') // true
regExp.test('12') // true
regExp.test('123') // true
regExp.test('1234') // false

量詞搭配 ? 的用法

(量詞指的是 {n,m} + * ? 這幾個)

用例子解說比較清楚:

1
2
3
const text = `Lorem Ipsum *star* is simply dummy text of the *burst* and *stream* industry.`
const regExp = /\*.{0,100}\*/g
text.match(regExp) // ?

如果你這樣寫的話,意思是「* 之間可以夾 0 ~ 100 個連續的任意字元」,不過這樣子其實有一個以上的符合結果:

  1. *star is simply dummy text of the burst and stream*
  2. *star is simply dummy text of the burst and *
  3. *star is simply dummy text of the burst*
  4. *star*

在量詞沒有搭配 ? 來使用的時後,text.match(regExp) 的結果會是 ['*star* is simply dummy text of the *burst* and *stream*'],這是因為量詞預設會先從匹配數量「最多」的那個開始抓。所以 match 會先拿到第一個結果,並回傳對應的陣列。

如果現在加上 ? (/\*.{0,100}?\*/g),結果就會從匹配數量「最少」的那個開始抓:

  1. *star*
  2. *burst*
  3. *stream*

*star* 中不會再有其他能夠匹配的可能,所以才說是匹配數量少,而 *star* is simply dummy text of the *burst* and *stream* 中包含了所有能夠匹配的可能,所以才說是匹配數量最多。

(因為這邊有用 g,這個修飾子,所以找到第一個後還會在往後找)

因為大部分的情況下我們應該會比較想要把資料整理成這樣,所以這個搭配 ? 的用法要學會怎麼用。

搭配 String 方法使用

match() 回傳符合條件的結果陣列,沒有找到符合對象回傳 null。

設定「包含 1 個數字」,「包含英文數字底線」的規則:

1
2
3
4
5
const str = 'hello'
const regExpA = /\d{1}/
const regExpB = /\w/g
str.match(regExpA) // null
str.match(regExpB) // ['h', 'e', 'l', 'l', 'o']

search() 回傳第一個符合條件對象的索引值,沒有找到符合對象回傳 -1。

設定「包含 1 個數字」,「包含 h」的規則:

1
2
3
4
5
const str = 'hello'
const regExpA = /\d{1}/
const regExpB = /\h/
str.search(regExpA) // -1
str.search(regExpB) // 0

replace() 把符合條件的對象的值做替換,沒有符合的對象就回傳原字串。接收兩個參數,第一個是正規表達式,第二個是要替換的值。

設定「包含任意數字」,「包含任意英文數字底線」的規則:

1
2
3
4
5
const str = 'hello'
const regExpA = /\d/
const regExpB = /\w/
str.replace(regExpA, 1) // 'hello'
str.replace(regExpB, 1) // '1ello'

一些基礎範例

設定「起始字串為 ab」的規則:

1
2
3
const regExp = /^ab/
regExp.test('abcdefg') // true
regExp.test('cccabc') // false

設定「結尾字串為 ab」的規則:

1
2
3
const regExp = /ab$/
regExp.test('abcdefg') // false
regExp.test('cccab') // true

設定「包含 ab 裡夾一個任意字元」的規則:

1
2
3
const regExp = /a.b/
regExp.test('a1234b') // false
regExp.test('aMb') // true

注意一個 . 代表的是一個字元。

設定「包含 任何數字」的規則:

1
2
3
4
const regExp = /\d/
regExp.test('123456') // true
regExp.test('abc') // false
regExp.test('abc123') // true

設定「包含 任何英文數字底線」的規則:

1
2
3
4
5
const regExp = /\w/
regExp.test('123456') // true
regExp.test('abc') // true
regExp.test('abc123') // true
regExp.test('?') // false

設定「包含 任何空白字元」的規則:

1
2
3
4
const regExp = /\s/
regExp.test('1 2 3') // true
regExp.test('a b c') // true
regExp.test('?') // false

設定「包含 a b 」的規則:

1
2
3
4
const regExp = /a|b/
regExp.test('123') // false
regExp.test('ac') // true
regExp.test('bc') // true

設定「包含 1 到 5」的規則:

1
2
3
const regExp = /[1-5]/
regExp.test('1239') // true
regExp.test('6') // false

想學更多可以參考的文章

參考資料

Day30 什麼是 RegExp 正則表達式 ?
十五分鐘認識正規表達式,解決所有文字難題
不可見字元的坑

正則表達式的實戰演練 mentor-program-day04
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×