说明:不同语言(Java/Python/.NET)少量语法有差异,标注【JS专属】【不支持JS】;前端 RegExp、String.match/replace/test 直接可用。 正则两大写法:
// 字面量(推荐,/pattern/flags) const reg = /abc/i // 构造函数(字符串要转义 \ → \) const reg = new RegExp('abc', 'i') "`
一、修饰符(Flags 标志)
| 标志 | 名称 | 说明 |
|---|---|---|
| g | global | 全局匹配,找到所有结果,不是只匹配第一个 |
| i | ignoreCase | 忽略大小写 |
| m | multiline | 多行模式:^ 匹配行首、$ 匹配行尾(不是整个字符串首尾) |
| s | dotAll | . 可以匹配换行符 \n(JS ES2018+) |
| u | unicode | 开启Unicode模式,正确处理emoji、生僻字 |
| y | sticky | 粘性匹配,从 lastIndex 位置开始紧挨着匹配 |
二、元字符(特殊字符)
这些字符有特殊含义,如果要匹配字符本身 ,必须加反斜杠 `` 转义:
. \ / * + ? | ( ) [ ] { } ^ $
| 元字符 | 含义 |
|------|----------------------------|---|
| . | 匹配任意单个字符(除换行 \n;开启s后包含换行) |
| \ | 转义符,把特殊字符变成普通字符,或者引出转义序列 |
| \ | 开头;多行模式下为每行开头 |
| $ | 结尾;多行模式下为每行结尾 |
| | | |
| () | 分组、捕获组;也用于优先级 |
| \[\] | 字符集,匹配括号内任意一个字符 |
| {} | 量词,限定重复次数 |
| * | 量词:0次或多次 |
| + | 量词:1次或多次 |
| ? | 量词:0次或1次;也用来开启非贪婪、正向预查 |
三、字符集 [] 与字符范围
[abc]:匹配 a、b、c 任意一个[a-z]:小写字母 a~z[A-Z]:大写字母 A~Z[0-9]:数字 0~9[a-zA-Z0-9]:字母+数字[^abc]:取反 ,匹配除a/b/c以外任意字符(^在[]里面是取反,外面是行首)[.-]:-放在开头/结尾就是普通减号,不会当成范围
⚠️ 在
[]里面:. * + ? ()不需要转义
四、预定义字符类(简写)
| 简写 | 等价 | 说明 |
|---|---|---|
| \d | 0-9 | 数字 |
| \D | \^0-9 | 非数字 |
| \w | a-zA-Z0-9_ | 单词字符:字母、数字、下划线 |
| \W | \^a-zA-Z0-9_ | 非单词字符 |
| \s | \\t\\n\\r\\f\\v | 空白:空格、制表符、换行、回车 |
| \S | \^ \\t\\n\\r\\f\\v | 非空白 |
| \n | 换行符 | line feed |
| \r | 回车符 | carriage return |
| \t | 制表符 Tab | |
| \b | 单词边界 | 单词和非单词交界处(不占字符,零宽) |
| \B | 非单词边界 | 不是单词边界 |
重点:
\b是零宽 ,不消耗字符,比如/\bcat\b/匹配独立单词 cat,不匹配 category
五、量词(重复次数)
| 写法 | 含义 |
|---|---|
| {n} | 恰好 n 次 |
| {n,} | 至少 n 次 |
| {n,m} | n ~ m 次(包含两端) |
| * | {0,} 0次或多次 |
| + | {1,} 1次或多次 |
| ? | {0,1} 0次或1次 |
贪婪 vs 非贪婪(非常高频坑)
默认贪婪匹配 :尽可能多匹配;在量词后面加 ? → 非贪婪(尽可能少匹配)
\d+贪婪:1234→ 匹配1234\d+?非贪婪:1234→ 先匹配1示例:
示例:
css
'<a>1</a><a>2</a>'.match(/<a>.*</a>/) // 贪婪,拿到全部
'<a>1</a><a>2</a>'.match(/<a>.*?</a>/) // 非贪婪,分开匹配
六、分组(Capture Group 捕获组)
1. 捕获组 (pattern)
- 括号内匹配到的内容会单独捕获,可以反向引用、提取
- 编号:从左到右
$1 $2 $3 ...
ini
const reg = /(\d{4})-(\d{2})-(\d{2})/
const res = '2026-11-11'.match(reg)
// res[1] = 2026,res[2]=11,res[3]=11
替换时使用:
dart
'2026-11-11'.replace(reg, '$2/$3/$1') // → 11/11/2026
2. 非捕获组 (?:pattern)
只分组、不捕获,不占用 $1 $2 编号,性能更好
makefile
/(?:abc|def)123/
3. 命名捕获组【ES2018+ JS支持】(?<name>pattern)
给分组起名字,可读性强
javascript
const reg = /(?<year>\d{4})-(?<month>\d{2})/
const m = '2026-11'.match(reg)
console.log(m.groups.year, m.groups.month)
4. 反向引用 \1 \2
在正则内部引用前面捕获到的分组内容 /(\w)\1/ → 匹配连续重复字符,如 aa、bb
注意:正则字面量里
\1;字符串构造正则要写\1
七、零宽断言(预查,零宽,不消耗字符,JS ES2018完整支持)
零宽 = 只做判断,不把字符吞进匹配结果
| 语法 | 名称 | 含义 |
|---|---|---|
| (?=expr) | 正向先行断言 | 后面必须是 expr |
| (?!expr) | 负向先行断言 | 后面不能是 expr |
| (?<=expr) | 正向后行断言 | 前面必须是 expr |
| (?<!expr) | 负向后行断言 | 前面不能是 expr |
示例:
ruby
// 数字后面带px,只提取数字,不要px '100px 20rem'.match(/\d+(?=px)/g) // [100]
// 前面是¥的数字 '¥99,abc88'.match(/(?<=¥)\d+/g) // [99]
// 不能以0开头的数字(先行) /^(?!0)\d+$/
八、注释与优先级
- 优先级(从高到低) `` →
()、(?...)→[]→ 量词* + ? {}→^ $ \b→| - 注释:
(?#注释)【⚠️ JS原生RegExp不支持 】 JS想写注释:用x修饰符的是其他语言(PCRE),JS不支持,只能分开写注释
九、JS 常用正则方法
String 方法
-
str.match(reg):匹配,返回数组;不带g只返回第一个+分组;带g返回全部匹配结果(无分组) -
str.matchAll(reg):【ES2020】带g,返回迭代器,同时拿到分组,推荐复杂提取 -
str.replace(reg, newVal|fn):替换,支持$1 $2 $& $' $" -
-
<!--MATH_PH_1-->1:分组1 -
$`:匹配内容前面文本
-
$':匹配内容后面文本
-
-
str.search(reg):返回匹配下标,找不到-1,不支持g -
str.split(reg):按正则分割
RegExp 对象方法
reg.test(str):返回布尔,是否匹配(⚠️ 带g时会变动 lastIndex,坑很多!)reg.exec(str):一次匹配,返回匹配数组+分组;带g会自动向后走 lastIndex
⚠️ 大坑:
/abc/g反复 test 会因为 lastIndex 导致时而true时而false
十、常用正则模板(开箱即用)
javascript
// 手机号(国内11位)
/^1[3-9]\d{9}$/
// 邮箱
/^[\w-]+(.[\w-]+)*@([\w-]+.)+[a-zA-Z]{2,7}$/
// 纯数字
/^\d+$/
// 纯字母
/^[a-zA-Z]+$/
// 数字+字母,6-16位(密码简单校验)
/^[a-zA-Z0-9]{6,16}$/
// 中文(UTF-8)
/^[\u4e00-\u9fa5]+$/
// URL简易匹配
/^https?://[^\s]+/
// 身份证(18位)
/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/
十一、常见踩坑清单
.不匹配换行,需要加s标志/./s^ $是字符串首尾,多行模式m才变成行首尾[]中. * + ?不用转义;-放中间会变成范围- 量词默认贪婪,需要
?开启非贪婪 - 后行断言
(?<=)老浏览器不支持(IE完全不支持) \w包含下划线,很多人误以为只是字母数字- 构造函数
new RegExp字符串里面 `` 必须双写\d test()+g全局标志,lastIndex 状态残留
十二、PCRE / .NET / Python 差异简要提示
- PCRE(PHP):支持
(?#注释)、x宽松模式、递归(?R) - .NET:后行断言支持不定长;JS后行断言只能固定长度
- Python re:
re.VERBOSE宽松注释模式,re.A控制 \w 范围