正则表达式

掌握JavaScript正则表达式的语法、方法和应用

正则表达式简介

正则表达式(Regular Expression)是用于匹配字符串中字符组合的模式。在JavaScript中,正则表达式也是对象。

创建正则表达式

创建正则表达式
// 字面量形式
const regex1 = /pattern/flags;

// 构造函数形式
const regex2 = new RegExp('pattern', 'flags');

正则表达式语法

字符类别

字符 描述 示例
. 匹配除换行符之外的任何单个字符 /a.c/ 匹配 "abc"、"a c"
\d 匹配数字字符,等价于 [0-9] /\d/ 匹配 "123" 中的 "1"
\D 匹配非数字字符,等价于 [^0-9] /\D/ 匹配 "a123" 中的 "a"
\w 匹配字母、数字或下划线,等价于 [A-Za-z0-9_] /\w/ 匹配 "hello" 中的 "h"
\W 匹配非字母、数字或下划线,等价于 [^A-Za-z0-9_] /\W/ 匹配 "hello!" 中的 "!"
\s 匹配空白字符(空格、制表符、换行符等) /\s/ 匹配 "hello world" 中的空格
\S 匹配非空白字符 /\S/ 匹配 "hello world" 中的 "h"

量词

字符 描述 示例
* 匹配前一个表达式0次或多次 /bo*/ 匹配 "boooo" 中的 "boooo"
+ 匹配前一个表达式1次或多次 /a+/ 匹配 "candy" 中的 "a"
? 匹配前一个表达式0次或1次 /e?le?/ 匹配 "angel" 中的 "el"
{n} 匹配前一个表达式恰好n次 /a{2}/ 匹配 "candy" 中的 "a"
{n,} 匹配前一个表达式至少n次 /a{2,}/ 匹配 "caandy" 中的 "aa"
{n,m} 匹配前一个表达式至少n次,最多m次 /a{1,3}/ 匹配 "candy" 中的 "a"

边界

字符 描述 示例
^ 匹配输入的开始 /^A/ 匹配 "An E" 中的 "A"
$ 匹配输入的结束 /t$/ 匹配 "eat" 中的 "t"
\b 匹配单词边界 /\bno/ 匹配 "at noon" 中的 "no"
\B 匹配非单词边界 /\Bno/ 匹配 "at noon" 中的 "noon"

正则表达式标志

标志 描述
g 全局搜索
i 不区分大小写搜索
m 多行搜索
s 允许 . 匹配换行符
u 使用unicode码的模式进行匹配
y 执行"粘性"搜索,匹配从目标字符串的当前位置开始

正则表达式方法

RegExp对象方法

方法 描述 示例
test() 测试字符串是否匹配正则表达式,返回布尔值 /hello/.test("hello world") 返回 true
exec() 执行搜索匹配,返回结果数组或null /hello/.exec("hello world") 返回 ["hello"]

String对象方法

方法 描述 示例
match() 返回匹配结果的数组 "hello".match(/hello/) 返回 ["hello"]
matchAll() 返回所有匹配结果的迭代器 "hello hello".matchAll(/hello/g) 返回迭代器
search() 测试字符串是否匹配,返回匹配的索引 "hello".search(/hello/) 返回 0
replace() 替换匹配的子字符串 "hello".replace(/hello/, "hi") 返回 "hi"
replaceAll() 替换所有匹配的子字符串 "hello hello".replaceAll(/hello/g, "hi") 返回 "hi hi"
split() 使用正则表达式或固定字符串分隔字符串 "hello world".split(/\s/) 返回 ["hello", "world"]

常用正则表达式示例

邮箱验证
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
console.log(emailRegex.test("user@example.com")); // true
console.log(emailRegex.test("invalid-email"));    // false
手机号验证
const phoneRegex = /^1[3-9]\d{9}$/;
console.log(phoneRegex.test("13812345678")); // true
console.log(phoneRegex.test("12345678901")); // false
URL提取
const urlRegex = /https?:\/\/[^\s/$.?#].[^\s]*/g;
const text = "Visit https://example.com and http://test.org";
console.log(text.match(urlRegex)); // ["https://example.com", "http://test.org"]
密码强度验证
// 至少8个字符,包含大小写字母和数字
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/;
console.log(passwordRegex.test("Password123")); // true
console.log(passwordRegex.test("weakpass"));    // false

分组和捕获

捕获组
const dateRegex = /(\d{4})-(\d{2})-(\d{2})/;
const match = dateRegex.exec("2023-10-05");
console.log(match[0]); // "2023-10-05"
console.log(match[1]); // "2023"
console.log(match[2]); // "10"
console.log(match[3]); // "05"
命名捕获组
const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = dateRegex.exec("2023-10-05");
console.log(match.groups.year);  // "2023"
console.log(match.groups.month); // "10"
console.log(match.groups.day);   // "05"
非捕获组
const regex = /(?:abc){2}/;
console.log(regex.test("abcabc")); // true
// 不会创建捕获组,match[1]为undefined

实践练习

练习代码
// 练习1: 验证身份证号
const idCardRegex = /^\d{17}[\dXx]$/;
console.log(idCardRegex.test("110101199001011234")); // true
console.log(idCardRegex.test("11010119900101123X")); // true
console.log(idCardRegex.test("12345678901234567"));  // false

// 练习2: 提取HTML标签
const tagRegex = /<(\w+)[^>]*>/g;
const html = "<div><p>Hello</p></div>";
const tags = html.match(tagRegex);
console.log(tags); // ["<div>", "<p>", "</p>", "</div>"]

// 练习3: 格式化电话号码
function formatPhone(phone) {
    return phone.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3');
}
console.log(formatPhone("13812345678")); // "138-1234-5678"

常见问题与解答

1. 贪婪匹配与非贪婪匹配有什么区别?

贪婪匹配会匹配尽可能长的字符串,而非贪婪匹配(在量词后加?)会匹配尽可能短的字符串。

贪婪匹配 vs 非贪婪匹配
const greedy = /<.*>/;
const nonGreedy = /<.*?>/;
const str = "<div>content</div>";

console.log(str.match(greedy)[0]);     // "<div>content</div>"
console.log(str.match(nonGreedy)[0]);  // "<div>"

2. 如何转义正则表达式中的特殊字符?

使用反斜杠\来转义特殊字符,如\.匹配字面点号,\\匹配字面反斜杠。

3. test()和exec()方法有什么区别?

test()方法返回布尔值,只检查是否有匹配;exec()方法返回匹配结果的详细信息,包括捕获组。

4. 什么时候使用字面量形式,什么时候使用构造函数?

当正则表达式模式固定时,使用字面量形式更简洁高效;当模式需要动态构建时,使用构造函数形式。

下一步学习

掌握了正则表达式后,接下来可以学习: