JavaScript中的正則表達式:文本處理的瑞士軍刀
在編程世界中,正則表達式(Regular Expression,簡稱RegExp)被譽為“文本處理的瑞士軍刀”。它能夠高效地完成字符串匹配、替換、提取和驗證等任務。無論是前端開發中的表單驗證,還是后端數據清洗,正則表達式都扮演著不可或缺的角色。本文將帶你深入淺出地了解JavaScript中的正則表達式,從基礎語法到高級技巧,助你掌握這一強大工具。
一、正則表達式的“身份證”:創建方式
在JavaScript中,正則表達式可以通過兩種方式創建:
1. 字面量方式
字面量方式是最直觀的創建方式,使用斜杠 /
包裹模式,并附加標志(flags):
const regex1 = /pattern/flags;
- pattern:定義匹配規則,例如
/abc/
表示匹配字符串 “abc”。 - flags:控制匹配行為,常見的標志包括:
g
(全局匹配):匹配所有符合條件的內容。i
(忽略大小寫):匹配時不區分大小寫。m
(多行匹配):將輸入字符串視為多行文本。
示例:
const regex = /\d+/g; // 匹配所有數字
console.log("123abc456".match(regex)); // 輸出 ["123", "456"]
2. 構造函數方式
通過 RegExp
構造函數動態創建正則表達式,適用于需要動態拼接模式的場景:
const regex2 = new RegExp('pattern', 'flags');
注意:構造函數中,特殊字符需要雙重轉義(如 \d
需要寫成 \\d
)。
示例:
const pattern = "\\d+"; // 匹配數字
const flags = "g";
const regex = new RegExp(pattern, flags);
console.log("123abc456".match(regex)); // 輸出 ["123", "456"]
二、正則表達式的核心語法:規則的“密碼本”
1. 元字符:賦予正則表達式“魔法”的符號
元字符是正則表達式中具有特殊含義的符號,它們能顯著提升匹配的靈活性。以下是一些常見元字符:
.
:匹配除換行符外的任意單個字符。*
:匹配前一個元素 0次或多次。+
:匹配前一個元素 1次或多次。?
:匹配前一個元素 0次或1次。^
:匹配字符串的開頭。$
:匹配字符串的結尾。\d
:匹配任意數字(等價于[0-9]
)。\w
:匹配字母、數字或下劃線(等價于[a-zA-Z0-9_]
)。\s
:匹配任意空白字符(空格、制表符、換行符等)。
示例:
// 匹配以 "http" 開頭、以 ".com" 結尾的字符串
const urlRegex = /^http.*\.com$/;
console.log(urlRegex.test("https://example.com")); // true
2. 量詞:控制匹配次數的“節拍器”
量詞用于定義某個模式出現的次數,是正則表達式中最強大的工具之一:
語法 | 含義 |
---|---|
{n} | 恰好匹配 n 次 |
{n,} | 至少匹配 n 次 |
{n,m} | 匹配 n 到 m 次 |
* | 等價于 {0,} |
+ | 等價于 {1,} |
? | 等價于 {0,1} |
示例:
// 匹配 5~10 位數字
const phoneRegex = /^\d{5,10}$/;
console.log(phoneRegex.test("123456")); // true
3. 字符類:定義“選項菜單”的快捷方式
字符類使用方括號 []
包裹,表示匹配其中任意一個字符:
[abc]
:匹配a
、b
或c
。[a-z]
:匹配任意小寫字母。[^a-z]
:匹配非小寫字母的字符(^
表示取反)。[0-9A-F]
:匹配十六進制數字。
示例:
// 匹配 RGB 顏色代碼(如 #FF0000)
const colorRegex = /^#[0-9A-Fa-f]{6}$/;
console.log(colorRegex.test("#123ABC")); // true
4. 分組與捕獲:提取信息的“集裝箱”
使用圓括號 ()
對模式分組,不僅能增強匹配邏輯,還能捕獲匹配到的子串:
- 捕獲組:通過
$1
、$2
等引用匹配內容。 - 非捕獲組:使用
(?:...)
表示僅分組,不捕獲。
示例:
// 提取日期中的年月日
const dateRegex = /(\d{4})-(\d{2})-(\d{2})/;
const match = dateRegex.exec("2025-06-04");
console.log(match[1], match[2], match[3]); // 輸出 2025 06 04
5. 邊界匹配:定位文本的“坐標系”
邊界匹配符幫助我們精準定位字符串的開始、結束或單詞邊界:
^
:匹配字符串的開頭。$
:匹配字符串的結尾。\b
:匹配單詞邊界(如空格或標點)。\B
:匹配非單詞邊界。
示例:
// 驗證郵箱格式(簡單版)
const emailRegex = /^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/;
console.log(emailRegex.test("user@example.com")); // true
三、高級技巧:正則表達式的“超能力”
1. 貪婪與非貪婪匹配
正則表達式默認是貪婪匹配(盡可能多地匹配字符),可以通過 ?
改為非貪婪匹配(盡可能少地匹配)。
示例:
const text = "<div><span>Hello</span></div>";
const greedyRegex = /<.*>/; // 貪婪匹配
const nonGreedyRegex = /<.*?>/; // 非貪婪匹配
console.log(greedyRegex.exec(text)[0]); // 整個字符串
console.log(nonGreedyRegex.exec(text)[0]); // 第一個 <div>
2. 預查(Lookaround):條件匹配的“隱形眼鏡”
預查允許我們檢查某個位置是否滿足條件,而不消耗字符:
- 正向預查:
(?=...)
(匹配后面必須滿足的條件)。 - 負向預查:
(?!...)
(匹配后面不能滿足的條件)。 - 正向后顧:
(?<=...)
(匹配前面必須滿足的條件)。 - 負向后顧:
(?<!...)
(匹配前面不能滿足的條件)。
示例:
// 匹配后面跟著 "px" 的數字
const pxRegex = /\d+(?=px)/;
console.log(pxRegex.exec("100px 200em")); // 輸出 ["100"]
3. 命名捕獲組:讓結果更易讀
在ES2018中,可以通過 ?<name>
為捕獲組命名,提升代碼可讀性:
示例:
const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = dateRegex.exec("2025-06-04");
console.log(match.groups.year); // 輸出 "2025"
四、實戰場景:正則表達式的“用武之地”
1. 表單驗證
正則表達式是表單驗證的利器,可以快速判斷用戶輸入是否符合預期格式:
// 驗證手機號(中國手機號格式)
const phoneRegex = /^1[3-9]\d{9}$/;
function validatePhone(input) {return phoneRegex.test(input);
}
2. 數據提取
從文本中提取關鍵信息(如日志分析、爬蟲):
// 提取 HTML 標簽中的內容
const htmlRegex = /<(\w+)>(.*?)<\/\1>/g;
let match;
while ((match = htmlRegex.exec("<div>Hello</div>")) !== null) {console.log(`標簽: ${match[1]}, 內容: ${match[2]}`);
}
3. 文本替換
通過 replace()
方法實現復雜的替換邏輯:
// 將所有 "JavaScript" 替換為 "JS"
const text = "JavaScript is awesome! Learn JavaScript.";
const replacedText = text.replace(/JavaScript/g, "JS");
console.log(replacedText); // "JS is awesome! Learn JS."
五、注意事項:避免“踩坑”的指南針
-
性能問題
復雜的正則表達式可能導致性能問題,尤其是涉及大量回溯時。建議通過非貪婪匹配、減少嵌套等方式優化。 -
安全性
在處理用戶輸入時,避免直接使用用戶輸入構建正則表達式,防止正則表達式注入攻擊。 -
可讀性
復雜的正則表達式難以維護。可以通過注釋、拆分邏輯或使用工具(如 Regex101)進行調試。
六、結語:從入門到精通的階梯
正則表達式是文本處理的強大工具,但它的學習曲線較為陡峭。掌握基礎語法后,建議通過實際項目不斷練習,并借助在線工具(如 RegExr)進行調試和優化。隨著熟練度的提升,你會發現正則表達式不僅能解決日常問題,還能成為你代碼中的“優雅解法”。
最后送大家一句話:
“正則表達式是一門藝術,也是開發者必備的技能之一。實踐是掌握它的最佳途徑!”
希望這篇文章能為你打開正則表達式的大門,未來在代碼中游刃有余!