iT邦幫忙

2021 iThome 鐵人賽

DAY 6
1
Modern Web

前端藏寶圖系列 第 6

深不可測的海 - Regular Expression

使用終端機搜尋特定字串時,大家一定用過 grep 這個指令吧~
但你有想過 grep 為什麼叫 grep 嗎?
沒有的話很正常,因為我也從沒想過,直到在查找正規表達式時意外發現了他的身世/images/emoticon/emoticon37.gif

根據無所不知的維基百科:

grep名稱來自於g/re/p(globally search a regular expression and print,以正規表示式進行全域尋找以及列印)

看來電腦的世界裡regex真是無所不在呢...../images/emoticon/emoticon06.gif
如果你跟我一樣是regex旱鴨子的話,別怕!這篇文章不會讓你直接進泳池的,我們先在泳池邊踢水就好,暖身好了的話,就開始吧~

基本概念

在JS中,正規表達式是一個物件,有兩種方式可以建立它。

  1. 用建構器創建 let pattern = new RegExp('BBQ');
  2. 用字面值語法建立 (比較常使用這種)let pattern = /BBQ/;

那要怎麼樣確認一串文字中有我們要的資訊呢?
可以使用RegExp.test(String) ,如果文字中有符合表達式定義好的規則就回傳true,沒有符合就回傳false,先來看個簡單的範例:
註:推薦使用regex101

let pattern = /BBQ/;

/BBQ/.test('I want to eat bbQ.'); // false
/BBQ/.test('BBQ BBQ BBQ.'); //true,但只會比對到第一個符合的

看樣子,正規表達式在意大小寫呢!要改變比對模式的話,可以使用flag
這些flag可以單獨也可以合併使用。

用來調整搜尋方式的旗標flags

  • g: 只要符合的全部找出來,如果沒有設定,找到第一個符合的就停止比對
  • i: 忽略大小寫
  • m: 多行文字比對
/BBQ/i.test('I want to eat bbQ. hahaha.'); // true
/BBQ/ig.test('BBQ bbQ BBQ.'); // true,全部都會比對到

用來指定位置的錨點 anchor

上面的例子中,無論BBQ出現在哪個位置都無所謂,但如果要限制文字出現的位置呢?

  • ^: 匹配字串的開頭
  • $: 匹配字串的結尾

/^BBQ/.test('I want to eat BBQ.'); // false
/^BBQ/.test('BBQ is yummy.'); //true

/BBQ$/.test('BBQ yo yo yo.'); // false 
/BBQ$/.test('We all love BBQ.'); // true 

從上面的例子可以知道,就算字串中有符合的文字,如果不在正規表達式指定的位置出現,就不會被比對。

用來提供範圍的中括號 []

如果不需要完全符合特定文字,只需要字串符合特定範圍呢?
比如說在中秋節發文的時候只要文字中有B和Q,就表示發文者可能很想吃烤肉(?)

/[BQ]/i.test('barbeque is good~'); // true

/BBQ/i.test('barbeque is good~'); // false,沒有用中括號,代表要完全匹配BBQ才回傳true

以下用常使用的範圍做範例:

//輸入必須要有數字
/[0-9]/.test('three two one'); // false
/[0-9]/.test('COVID-19'); // true

//輸入必須含有a-z的字母
/[a-z]/.test('123'); // false
/[a-z]/.test('COVID-19'); //false
/[a-z]/.test('abc'); //true 

在前面的指定匹配位置時提到了一個錨點符號^
這個符號如果出現在中括號時,就成了否定字元,概念很像JS中的邏輯運算子NOT!

大概是因為某些範圍在實務上經常使用,所以正規表達式中提供了字元類別來代表這些常用的字串範圍

  • \d: 任何的 ASCII 數字,相當於[0-9]
  • \D: 任何的 ASCII 數字以外的字元,也可以表示成[^0-9]
  • \w: 任何字詞字元,等同於 [A-Za-z0-9]
  • \W: 非字詞字元,也可表示成 [^A-Za-z0-9]
  • \s: 任何空白字元
  • 還有超級多,願意憋氣下水的朋友可以看看w3Schools的Metacharacters

指定重複次數 {} + *

當我們需要描述特定規則出現的次數,就得拜託重複字元幫忙了~

  • 出現至少n次,但不多於m次 {n, m}
let pattern = /\d{2,5}/;  -> 代表2到5位數

/\d{2,5}/.test('4'); // flase
/\d{2,5}/.test('1234'); // true
/\d{2,5}/.test('123456'); // 雖然回傳值是true,但只有比對12345,如果要限定只有2到5位數才回傳true,可以使用錨點(如下)

/^\d{2,5}$/.test('123456'); // false
/^\d{2,5}$/.test('423'); // true
  • 剛好出現n次 {n}
/^\w{3}$/.test('BBQ');  // true
/^\w{3}$/.test('BBQ '); // false, 因為結尾是空白字元
  • 出現至少一次,可多於一次 +
/^\d+$/.test(''); // flase
/^\d+$/.test('1'); // true
/^\d+$/.test('42'); // true
/^\d+$/.test('42school'); // false
  • 可有可無的 (出現次數 >= 0 ) *
/^\d*$/.test(''); // true
/^\d*$/.test('1'); // true

選項及群組字元

腳開始抽筋的朋友再撐一下,認識完最後的兩個字元就可以吃烤肉啦~

  • 選項字元 |
    • 選項的比對順序是由左而右,直到找到一個符合的為止
    • 如果左邊的選項有符合表達式的規則,則右邊的選項會被忽略
/BBQ|mooncake/.test('pomelo'); //flase
/BBQ|mooncake/.test('BBQ'); // true
/BBQ|mooncake/.test('mooncake'); //true
  • 群組字元 (...)

根據JS大全,括弧有數個用途,其中之一是把不同的項目歸組成一個子表達式,可以想成是一個個單元。我們實際看圖比較清楚。

首先我們先定義規則為開頭是四個數字,後面需緊跟著字詞字元,測試的字串分別為5252BBQ和777lucky。
可以看到右側的比對資訊欄中除了配對的字串外,還包含群組資訊,如果我們把規則中的括弧拿掉,就只出現比對的完整資料而已。


回到昨天還看不懂的魔法咒語 /^(a |an |the )/i
是不是好像沒那麼困難了呢,如果還是看不懂的話沒關係,先吃一波烤肉再說/images/emoticon/emoticon42.gif

參考資料

正規表示式 - 維基百科
grep - 維基百科
A quick and simple guide to JavaScript Regular Expressions
JavaScript大全 第七版


上一篇
就決定是你了 - 陣列系列III
下一篇
資料傳輸格式 JSON
系列文
前端藏寶圖30
0
wendy
iT邦新手 5 級 ‧ 2021-09-21 14:45:38

整理的很棒~~/images/emoticon/emoticon24.gif

Chiahsuan iT邦新手 5 級 ‧ 2021-09-21 14:50:04 檢舉

謝謝Wendy鼓勵~~期待明天跟你學客家話~~~/images/emoticon/emoticon47.gif

0
南國ㄟ安迪
iT邦新手 5 級 ‧ 2021-09-21 14:54:08

先按讚,以免別人以為我不懂QQ

Chiahsuan iT邦新手 5 級 ‧ 2021-09-21 15:01:36 檢舉

沒關係,先穿起泳褲,一起到泳池邊練踢水 /images/emoticon/emoticon01.gif

0
Hooo
iT邦新手 5 級 ‧ 2021-09-21 15:50:21

邊看邊踢得很開心

Chiahsuan iT邦新手 5 級 ‧ 2021-09-23 12:50:46 檢舉

/images/emoticon/emoticon79.gif

我要留言

立即登入留言