正则表达式
- 正则表达式用于定义一些字符串的规则
- 可以根据正则表达式来检测一个字符串是否符合规则
创建正则表达式
字面量方式
js
let reg = /abc/;
构造函数方式
js
let reg = new RegExp("abc");
修饰符(flags)
修饰符 | 含义 |
---|---|
g |
全局匹配 |
i |
忽略大小写 |
m |
多行模式 |
s |
dotAll 模式,. 匹配换行符 |
u |
支持 Unicode |
y |
粘性匹配,从 lastIndex 开始 |
元字符(Metacharacters)
字符 | 含义 |
---|---|
. |
匹配除换行符外的任意字符 |
^ |
匹配字符串开头 |
$ |
匹配字符串结尾 |
\d |
匹配数字 |
\D |
匹配非数字 |
\w |
匹配字母、数字、下划线 |
\W |
匹配非单词字符 |
\s |
匹配空白字符 |
\S |
匹配非空白字符 |
匹配单词边界 | |
\B |
匹配非单词边界 |
量词(Quantifiers)
符号 | 含义 |
---|---|
* |
匹配 0 次或多次 |
+ |
匹配 1 次或多次 |
? |
匹配 0 次或 1 次 |
{n} |
匹配 n 次 |
{n,} |
匹配至少 n 次 |
{n,m} |
匹配 n 到 m 次 |
贪婪与惰性匹配
js
// 贪婪匹配
/a.*b/
// 惰性匹配
/a.*?b/
分组与引用
分组
js
/(ab)+/
反向引用
js
/(.)/ // 匹配连续相同字符,如 "aa"
非捕获组
js
/(?:abc)/
命名捕获组(ES2018+)
js
const str = "2025-04";
const reg = /(?<year>\d{4})-(?<month>\d{2})/;
const result = str.match(reg);
console.log(result.groups.year); // 2025
断言(Assertions)
正向肯定断言
js
/\d(?=px)/ // 匹配后面是 px 的数字
正向否定断言
js
/\d(?!px)/ // 匹配后面不是 px 的数字
反向肯定断言(Lookbehind)
js
/(?<=\$)\d+/ // 匹配 $ 后的数字
反向否定断言
js
/(?<!\$)\d+/ // 匹配前面不是 $ 的数字
常用方法
RegExp 实例方法
js
const reg = /abc/;
reg.test("abc"); // true
reg.exec("abcdef"); // ["abc"]
字符串对象方法
js
"abc123".match(/\d+/g); // ["123"]
"abc123".search(/\d+/); // 3
"abc123".replace(/\d+/, "#"); // abc#
"1-2-3".split(/-/); // ["1", "2", "3"]
Unicode 与属性转义(ES2018+)
js
/\p{Script=Greek}/u
必须搭配 u
修饰符使用。
其他高级用法
多行匹配(m)
js
/^abc/m
粘性匹配(y)
js
const reg = /a/y;
reg.lastIndex = 1;
reg.exec("baaa"); // null,因为从位置 1 开始不是 "a"
🧠 正则表达式的执行原理
正则表达式通常由**NFA 引擎(非确定有限自动机)**或 DFA(确定型自动机)执行:
- NFA(大多数编程语言使用,如 JavaScript、Python):
- 从头到尾尝试多种路径(回溯)。
- 灵活,但可能效率低。
- DFA(如某些命令行工具):
- 不回溯,只尝试一种路径,性能更稳定但功能弱。
回溯的影响示例:
js
const regex = /(a+)+$/;
regex.test("aaaaaaaaaaaaaaaaaaaaa!"); // 极慢:回溯地狱
这类问题称为 Catastrophic Backtracking(灾难性回溯),匹配失败时会极大拖慢执行速度。
🧩 嵌套分组与命名分组深入用法
命名捕获组(ES2018+):
js
const str = "Name: Alice Age: 20";
const reg = /Name: (?<name>\w+) Age: (?<age>\d+)/;
const result = str.match(reg);
console.log(result.groups.name); // Alice
嵌套组合:
js
/((foo)(bar))\3/ // 匹配 "foobarbar"
组号从左至右分配,嵌套也会编号。
🔎 正向/反向断言的高级使用
正向肯定断言:
js
/\d(?=px)/g // 匹配紧跟 px 的数字
反向肯定断言(Lookbehind):
js
/(?<=\$)\d+/g // 匹配 $ 符号后面的数字
这些对提取特定前后缀的数据特别有用,如提取 CSS 数值、货币值等。
⚙️ 正则性能优化技巧
技巧 | 示例 |
---|---|
避免重复匹配 | 用 + 替代多个 * |
固定开头 | 使用 ^ 锚定 |
精确限定 | 使用 {m,n} 代替 .* |
惰性匹配 | 用 *? 替代贪婪 * |
非捕获组 | 用 (?:...) 提高效率 |
js
// 慎用
/.*foo.*bar.*/
// 更优写法
/^.*?foo.*?bar/
🛡️ 输入预处理与安全防护
XSS 防护示例:
js
const sanitized = input.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, "");
防 SQL 注入:
js
const hasSQL = /('|--|;|\b(select|insert|delete|update|drop|union)\b)/i.test(userInput);
调试技巧与工具推荐
调试技巧
- 多用
.test()
、.exec()
检查正则效果 - 控制台调试,结合
console.log
- 使用 IDE 高亮或在线工具预览匹配效果
在线工具推荐
名称 | 链接 |
---|---|
regex101 | https://regex101.com |
regexr | https://regexr.com |
regexper | https://regexper.com |
📚 值得掌握的正则表达式案例
目标 | 正则表达式 |
---|---|
匹配非重复字符 | ^(?!.*(.).*\1).+$ |
匹配 emoji | /[\uD800-\uDBFF][\uDC00-\uDFFF]/g |
解析 JSON 键值对 | `/"(["]+)":\s*("["]+" |
提取 HTML 属性 | /([a-zA-Z-]+)="([^"]*)"/g |
✅ 总结建议
- 正则表达式适合解决字符串匹配和提取问题,但可读性差时应加注释或分步骤处理。
- 建议多练常见应用场景如手机号、邮箱、URL、密码验证等。
- 工欲善其事,推荐配合可视化调试工具使用,效率更高。
一些常用的正则表达式
1. 手机号(中国)
js
/^1[3-9]\d{9}$/
2. 固定电话(带区号)
js
/^0\d{2,3}-?\d{7,8}$/
3. 邮箱地址
js
/^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}$/
4. 身份证号(中国第二代)
js
/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/
5. 邮政编码(中国)
js
/^\d{6}$/
6. 用户名(字母开头,4-16位,含字母数字下划线)
js
/^[a-zA-Z][a-zA-Z0-9_]{3,15}$/
7. 密码(至少包含数字和字母,长度6~20)
js
/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,20}$/