要檢查一個正規表達式,做法是把它套用在一段範例字串上,觀察它產生出來的相符結果、擷取群組,以及具名群組——對於 JavaScript 樣式而言,最快的做法是把這個正規表達式輸入到 Regex Tester 欄位中,切換你需要的旗標,並在你輸入的同時,閱讀下方結果中被標示出來的相符內容。
檢查一個正規表達式,是一個「建構—測試—微調」的循環,而不是一次到位的驗證。你寫出一個樣式,拿它去測試具代表性的輸入,然後不斷調整,直到相符結果與群組看起來完全正確為止。麻煩的地方在於,不同語言使用的正規表達式方言略有差異,因此一個在 Python 中能正常運作的樣式,在 JavaScript 中可能表現不同。Regex Tester 使用的是瀏覽器原生的 JavaScript RegExp 引擎,這代表一個在這個測試工具中能相符的樣式,在 JavaScript、TypeScript 與 Node 中,也會以同樣的方式相符——反之亦然。不需要安裝任何東西、不需要上傳任何東西,也不需要註冊任何帳號;這個工具完全在你的瀏覽器中,用本機端的 JavaScript 運作,因此你的樣式與測試文字會一直留在你自己的裝置上。

一次正規表達式檢查在做的三件事
「檢查一個正規表達式」通常代表下面三件事之一,而同一個工具可以回答全部三個問題。
- 驗證: 這個樣式是否接受合法輸入、拒絕不合法輸入?你會拿幾個正例與反例去測試,藉此確認。
- 擷取: 這個樣式能不能擷取出我需要的欄位——日期、ID、價格、slug?你會檢視擷取群組與具名群組,確認結構是否正確。
- 除錯: 為什麼我的樣式沒有回傳任何結果,或是回傳了錯誤的結果?你會查看相符細節,確切了解哪些字元相符、哪些群組有參與相符。
這三項任務都共用同一套工作流程:輸入樣式、指向範例文字,然後檢視引擎回報的結果。Regex Tester 就是圍繞著這套工作流程打造的,因此本篇指南接下來,會逐一說明如何針對每一種情況使用它。
用 Regex Tester 測試一個樣式
這個介面有三個可以互動的部分:一個樣式輸入框、一列旗標,以及一個測試字串區域。以下是典型檢查流程的操作順序。
- 在 /…/ 欄位中輸入或貼上這個樣式。 你不需要自己加上斜線——只要你切換一個旗標,這個測試工具就會自動幫你把這個字面值包起來。
- 切換你需要的旗標。 常見的選擇是用 g 找出所有相符結果,用 i 忽略大小寫,以及在你的錨點需要在每一行都觸發時使用 m。
- 輸入或貼上你的測試字串。 使用一段真實的樣本,裡面既包含你想要相符的內容,也包含幾個你不想要相符的內容,這樣你才能確認這個樣式不會過度相符。
- 閱讀被標示出來的相符結果。 每一個相符結果,都會在你的測試字串中以行內方式標示出來,而一個細節面板會把每一個結果拆解開來:起始索引、完整相符的文字、依編號排列的擷取群組,以及任何用 (?<name>…) 寫出來的具名群組。
- 一次微調一個記號。 更改一個量詞、替換一個字元類別,或加上一個錨點,然後在你輸入的同時觀察標示如何更新——這是建立對每個部分作用直覺最快的方法。
如果一個樣式只找到第一筆相符結果,但你原本預期會有好幾筆,最常見的原因是忘了加 g 旗標。少了它,JavaScript 會在第一筆相符結果處就停下來;有了它,這個引擎會回報字串中的每一筆相符結果。
六個 JavaScript 旗標,以及它們各自的作用
JavaScript 的 RegExp 建構函式,公開了六個旗標,而 Regex Tester 把它們全部都做成了切換選項。這一列旗標,會幫你重新組出 /pattern/flags 這個字面值,讓你可以把完全一致的表達式,直接複製進你的程式碼中。
| 旗標 | 名稱 | 它改變了什麼 |
|---|---|---|
| g | global | 找出字串中的每一筆相符結果,而不是只停在第一筆。 |
| i | ignore case | 讓字母的相符不區分大小寫:/abc/i 會相符「ABC」、「Abc」與「abc」。 |
| m | multiline | 讓 ^ 與 $ 錨定在每一行上,而不只是整個字串的開頭與結尾。 |
| s | dotAll | 讓句點 . 也能相符換行字元,而不只是其他任意字元。 |
| u | unicode | 啟用完整的 Unicode 處理,包括代理對與 Unicode 屬性跳脫序列。 |
| y | sticky | 只從 lastIndex 開始相符;當你要從左到右進行詞元化時很有用。 |
對於大多數日常的檢查工作,你只會需要 g,可能再加上 i。當你的輸入包含多行、而你想讓 ^…$ 相符每一行時,可以用 m;而當你的樣式需要跨越換行字元時,可以用 s。
解讀相符結果:擷取群組、具名群組,以及零寬度命中
測試字串下方的細節面板,正是你確認這個樣式是否如你所願的地方。有三件事值得仔細看看。
擷取群組 指的是括號內的子字串。它們依順序回報,從索引 1 開始,因此你樣式中的第一個 (…) 是群組 1,第二個是群組 2,以此類推。如果某個群組是可選的,而且在某一次相符中並未參與,這個測試工具會清楚標示出來,讓你能看出為什麼一個可選群組會回傳空值。
具名群組 使用 (?<name>…) 這種語法,會連同它們的數字位置一起被回報。它們讓你可以用一個可讀的名稱來引用一次擷取,而不是用一個索引,這在 String.match、matchAll,以及 replace 回呼函式中,維護起來要容易得多。
零寬度相符 是人們最容易卡住的地方。像 a*、^、\b,或是一個空樣式這樣的樣式,相符的是一個位置,而不是一個字元。搭配 g 旗標時,一個天真的迴圈如果對它們逐一相符,會永遠重複相符同一個空位置,並讓瀏覽器凍結。這個測試工具會安全地跳過每一個零寬度相符,並回報每一個位置而不會卡住,這對診斷用途來說,正是正確的行為。
快速正規表達式檢查的常見使用情境
人們啟動一個正規表達式測試工具最常見的原因,可以歸類成幾個實務上的類別。
- 驗證使用者輸入。 電子郵件、電話號碼、URL,以及 slug 樣式,都可以很快地拿真實與刁鑽的樣本來原型測試。
- 從文字中擷取欄位。 日期、ID、價格、日誌嚴重程度,以及類似的詞元,都可以很容易地用具名群組來擷取並標記。
- 為尋找並取代做原型測試。 先把一個候選樣式丟進這個測試工具裡,接著就能把同一個表達式用在 String.replace 或 replaceAll 中,不會有任何意外。
- 學習基本組成元件。 字元類別(\d、\w、\s 以及它們的否定形式)、量詞(*、+、?、{n,m})、錨點(^、$)、交替(|),以及前瞻((?=…)、(?!…)),都可以透過一次更改一個記號、並觀察標示如何更新,逐一揭露它們自己的作用。
有一個效能上的提醒值得記在心上:一個寫得不好的樣式,在某些輸入上,可能會觸發災難性回溯——也就是所謂的 ReDoS。在這個測試工具裡,這頂多只會拖慢你自己那個瀏覽器分頁;不會有任何東西在伺服器上執行,也不會有任何東西被分享出去。而在正式環境的程式碼中,實務上的重點是:把你的樣式錨定住,並在不受信任的輸入上,避免使用巢狀量詞。
值得優先嘗試的正規表達式基本組成元件
如果你還在學習這套語法,這個測試工具同時也能當成一個練習場。一份簡短的記號清單,讓你動手輸入並觀察,就足以建立一套可用的心智模型。
| 記號 | 它相符什麼 | 可以拿來試試看 |
|---|---|---|
| \d | 任何數字,0–9 | 「Order #4729 confirmed」 |
| \w | 任何單字字元(字母、數字、底線) | 「user_name-42」 |
| \s | 任何空白字元 | 含有空格與定位字元的多行輸入 |
| ^ 與 $ | 一行(搭配 m)或一個字串的開頭與結尾 | 像「BEGIN」與「END」這樣的行 |
| {n,m} | 重複 n 到 m 次之間 | 特定長度的單字 |
| (?=…) | 正向前瞻——斷言但不消耗字元 | 密碼規則與價格後綴 |
如果想看更完整的、仍在 JavaScript 方言範圍內的記號清單,Regex Cheat Sheet 是你實驗時一份很有用的參考資料。
不論你最後得到什麼樣式,只要在 Regex Tester 中確認過一次,你就可以把同一個 /pattern/flags 字面值,直接丟進 String.match、matchAll、replace,或是 RegExp 建構函式中,不會有任何意外——因為引擎是完全一樣的。
如果你正在權衡各種選項,How to Generate UUIDs in JavaScript 有詳細說明。