正则表达式语法详细总结
正则表达式(Regex/RegExp)语法详细总结
正则表达式是一套用于匹配、查找、替换、校验字符串的规则语法,被绝大多数编程语言、文本编辑器、数据库原生支持,核心是通过元字符定义匹配模式,实现精准高效的文本处理。
一、基础规则与必转义元字符
1. 普通字符
字母、数字、中文、下划线_等无特殊含义的字符,直接匹配自身,例如正则abc仅匹配字符串中的连续字符abc。
2. 特殊元字符(必须转义)
以下字符在正则中拥有专属语法含义,若要匹配字符本身,必须加反斜杠\转义:
. * + ? ^ $ | ( ) [ ] { } \示例:要匹配字符串中的.,正则需写为\.,而非.。
二、字符类(方括号表达式)
匹配方括号内的任意一个字符,单次匹配仅命中一个字符,是正则的基础匹配单元。
| 语法 | 说明 | 匹配示例 |
|---|---|---|
[abc] |
普通字符类,匹配a/b/c中的任意一个 | [abc]at 匹配aat/bat/cat |
[^abc] |
否定字符类,匹配除了a/b/c之外的任意字符 | [^abc]at 匹配dat/eat,不匹配aat/bat |
[a-z] |
范围字符类,匹配指定区间内的字符 | [0-9a-fA-F] 匹配16进制字符 |
. |
通配符,匹配除换行符\n外的任意单个字符(单行模式下可匹配换行) |
h.t 匹配hat/hot/h t,不匹配heet |
预定义字符类(简写)
系统预设的高频字符类,简化书写,所有预定义类均为单个字符匹配:
| 简写 | 等价写法 | 核心说明 |
|---|---|---|
\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] |
匹配任意非空白字符 |
关键注意:方括号内的特殊元字符,除
^(开头否定)、-(区间)、\(转义)、](闭合)外,其余均无需转义,例如[.]仅匹配.本身,而非任意字符。
三、量词(重复匹配)
控制前面的单个字符/分组的重复出现次数,是实现批量匹配的核心,分为3种匹配模式。
1. 基础量词语法
| 语法 | 匹配规则 | 典型场景 |
|---|---|---|
{n} |
前面的单元必须恰好出现n次 | 固定长度校验,如\d{6}匹配6位验证码 |
{n,} |
前面的单元至少出现n次,无上限 | 最小长度限制,如\w{6,}匹配至少6位单词字符 |
{n,m} |
前面的单元出现n~m次,包含n和m | 区间长度限制,如\d{8,16}匹配8-16位数字 |
* |
零次或多次,等价于{0,} |
可选重复内容,如a.*b匹配a开头、b结尾的任意字符串 |
+ |
一次或多次,等价于{1,} |
必选重复内容,如\d+匹配连续数字 |
? |
零次或一次,等价于{0,1} |
可选内容,如colou?r匹配color和colour |
2. 贪婪 vs 非贪婪(懒惰)模式
正则默认是贪婪模式:尽可能匹配最长的符合规则的字符串;
在量词后加?,切换为非贪婪模式:尽可能匹配最短的符合规则的字符串。
| 模式 | 语法 | 示例 | 匹配字符串a123b456b的结果 |
|---|---|---|---|
| 贪婪模式 | 量词默认 | a.*b |
匹配整个字符串a123b456b |
| 非贪婪模式 | 量词+? |
a.*?b |
仅匹配最短片段a123b |
3. 占有模式
在量词后加+,语法如*+/++/{n,m}+,匹配时一次性吞入所有符合规则的字符,匹配失败不回溯,性能更高,仅PCRE、Java等引擎支持,JS原生不支持。
四、锚点与边界匹配(零宽匹配)
零宽度核心特性:仅匹配字符串中的位置,不匹配任何字符,不消耗字符串长度,核心用于限定匹配内容的位置。
| 语法 | 名称 | 匹配规则 |
|---|---|---|
^ |
行开头锚点 | 匹配字符串的开头;多行模式m下,匹配每一行的开头 |
$ |
行结尾锚点 | 匹配字符串的结尾;多行模式m下,匹配每一行的结尾 |
\b |
单词边界 | 匹配单词字符(\w)和非单词字符(\W)之间的位置 |
\B |
非单词边界 | 匹配两个单词字符/两个非单词字符之间的位置,与\b相反 |
\A |
字符串绝对开头 | 仅匹配整个字符串的开头,不受多行模式m影响 |
\Z |
字符串结尾 | 仅匹配整个字符串的结尾,或结尾换行符前的位置,不受多行模式影响 |
\z |
字符串绝对结尾 | 仅匹配整个字符串的最末尾,忽略结尾换行符 |
核心示例:
^\d{6}$:匹配整个字符串恰好是6位数字,用于表单验证码校验\bhello\b:匹配独立单词hello,不匹配helloworld中的hellohello$:仅匹配一行末尾的hello
五、分组与捕获
用圆括号()将多个字符/规则打包为一个整体,可对整个分组施加量词、分支,同时可捕获分组匹配的内容供后续使用。
1. 捕获分组
普通括号()会将分组内匹配的内容捕获并存储,系统自动按左括号的顺序从1开始编号,0固定为整个正则匹配的完整内容。
| 语法 | 说明 | 示例 |
|---|---|---|
(pattern) |
普通捕获分组,自动编号 | (\d{4})-(\d{2})-(\d{2}):匹配日期,分组1=年,分组2=月,分组3=日 |
(?<name>pattern) |
命名捕获分组,自定义分组名 | (?<year>\d{4})-(?<month>\d{2}):给年、月分组命名,JS/Java/.NET支持 |
(?P<name>pattern) |
Python专属命名捕获分组 | Python中通过group('name')获取对应匹配内容 |
2. 非捕获分组
语法(?:pattern),仅用于分组打包,不捕获内容,不占用分组编号,适合仅需分组控制量词/分支、无需后续引用的场景,可节省内存、提升匹配效率。
示例:
(?:ab)+:匹配ab重复1次或多次(如ababab),但不捕获ab的内容http(?:s)?://:匹配http://和https://,s可选,无需捕获
3. 分支结构(或)
语法|,匹配|左右任意一个模式,优先级极低,低于量词和锚点,通常需配合分组使用。
示例:
- 正确写法:
gr(a|e)y,匹配gray和grey,精准限定分支范围 - 错误写法:
gra|ey,匹配gra或ey,而非预期的两个单词
六、反向引用
引用前面捕获分组匹配到的内容(而非模式本身),实现重复内容的精准匹配,是正则的核心进阶能力。
1. 编号反向引用
语法\数字,数字对应捕获分组的编号,例如\1引用第1个捕获组,\2引用第2个。
核心示例:
(\w+)\s+\1:匹配连续重复的单词,如hello hello、test test,\1严格匹配前面(\w+)捕获到的内容<(\w+)>.*?</\1>:匹配闭合HTML标签,如<div>123</div>,\1引用前面的标签名div
2. 命名反向引用
对应命名捕获组,不同引擎语法不同:
- JS/Java/.NET:
\k<name>,示例(?<tag>\w+).*?\k<tag> - Python:
(?P=name),示例(?P<tag>\w+).*?(?P=tag)
关键提醒:反向引用的是分组匹配到的具体内容,而非分组的规则。例如
(\d)\1匹配11、22,但不匹配12,因为\1必须和第一个分组的内容完全一致。
七、零宽断言(环视/Lookaround)
进阶零宽匹配,仅匹配位置,不消耗字符,核心是判断「当前位置的前后」是否符合指定模式,是实现精准条件匹配的核心能力。
| 断言类型 | 语法 | 匹配规则 | 核心说明 |
|---|---|---|---|
| 正向先行断言 | (?=pattern) |
匹配后面紧跟pattern的位置 | 向右看,符合条件才匹配 |
| 负向先行断言 | (?!pattern) |
匹配后面不紧跟pattern的位置 | 向右看,不符合条件才匹配 |
| 正向后行断言 | (?<=pattern) |
匹配前面紧跟pattern的位置 | 向左看,符合条件才匹配 |
| 负向后行断言 | (?<!pattern) |
匹配前面不紧跟pattern的位置 | 向左看,不符合条件才匹配 |
核心示例
- 正向先行断言:
\d+(?=元),匹配100元中的100,不匹配100块中的100 - 负向先行断言:
\d+(?!元),匹配100块中的100,不匹配100元中的100 - 正向后行断言:
(?<=¥)\d+,匹配¥100中的100,不匹配$100中的100 - 负向后行断言:
(?<!¥)\d+,匹配$100中的100,不匹配¥100中的100
高频实战场景
密码强度校验:必须同时包含大小写字母、数字,长度8-16位
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z0-9]{8,16}$- 多个先行断言叠加,分别校验必须包含小写、大写、数字,再匹配主体规则
兼容性说明
- 先行断言:所有主流引擎均支持
- 后行断言:JS ES2018+、Python 3.10+、Java、.NET支持;低版本JS/Python仅支持固定长度的后行断言,不支持
*/+等不定长规则
八、修饰符(标志位)
写在正则表达式的末尾,用于全局控制匹配模式,不同语言的写法略有差异(JS:/pattern/flags;Python:re.compile(pattern, flags))。
| 修饰符 | 全称 | 核心作用 |
|---|---|---|
i |
Ignore Case | 忽略大小写,匹配时不区分字母大小写 |
g |
Global | 全局匹配,找到所有符合规则的匹配项,而非仅第一个 |
m |
Multiline | 多行模式,^和$匹配每一行的开头和结尾,而非整个字符串 |
s |
Dot All / Singleline | 单行模式,通配符.可以匹配换行符\n,默认不匹配 |
u |
Unicode | Unicode模式,支持匹配4字节的Unicode字符(如emoji、生僻字) |
x |
Extended | 扩展模式,忽略正则中的空白字符,支持行内注释,提升可读性 |
示例:
/hello/i:匹配Hello、HELLO、hello/\d+/g:匹配字符串中所有的数字序列,而非仅第一个
九、特殊转义字符
用于匹配不可见字符、特殊编码字符,常用如下:
| 语法 | 匹配内容 |
|---|---|
\t |
水平制表符(Tab键) |
\n |
换行符 |
\r |
回车符 |
\f |
换页符 |
\v |
垂直制表符 |
\0 |
空字符(NULL) |
\xhh |
两位十六进制ASCII字符,如\x41匹配A |
\uhhhh |
四位十六进制Unicode字符,如\u4e2d匹配中文中 |
\cX |
控制字符,X为A-Z,如\cM匹配Ctrl+M(回车符) |
十、高级语法与特殊构造
以下为进阶语法,不同正则引擎的支持度差异较大,主流PCRE、Java、.NET支持,部分JS低版本不支持。
1. 条件匹配
语法:(?(id/name)yes-pattern|no-pattern)
含义:如果指定编号/名称的捕获组匹配成功,则匹配yes-pattern,否则匹配no-pattern,|no-pattern可选。
示例:(<)?a.*?(?(1)>):匹配<a href="xxx">或a href="xxx",如果开头有<,结尾必须有>。
2. 原子组(固化分组)
语法:(?>pattern)
含义:一次性吞入匹配的内容,匹配失败时不回溯,大幅提升正则性能,避免灾难性回溯。
示例:(?>a+)ab匹配aaaab时,先吞入所有a,发现后续无法匹配ab,直接失败,不回溯释放a。
3. 正则注释
语法:(?#注释内容)
含义:正则内的注释,不参与匹配,配合x修饰符可实现多行注释,提升复杂正则的可读性。
示例:\d{4}(?#年)-\d{2}(?#月)-\d{2}(?#日)
4. 递归匹配
语法:(?R)/(?0)
含义:递归引用整个正则表达式本身,用于匹配嵌套结构(如嵌套括号、嵌套HTML标签)。
示例:\(([^()]+|(?R))*\):匹配任意深度的嵌套括号,如(a(b(c)d)e)。
十一、正则运算符优先级(从高到低)
正则的匹配顺序由优先级决定,优先级从高到低排序如下,避免书写时出现逻辑错误:
- 转义符:
\ - 括号类:
()、(?:)、(?=)、[](方括号字符类) - 量词:
*、+、?、{n}、{n,}、{n,m} - 锚点与字符序列:
^、$、\b、普通字符、预定义字符类 - 分支结构:
|(或)
核心提醒:
|的优先级最低,若要限定分支范围,必须用括号包裹,否则会作用于整个正则的左右两侧。
十二、高频常用正则示例
| 场景 | 正则表达式 |
|---|---|
| 手机号(中国大陆) | ^1[3-9]\d{9}$ |
| 邮箱地址 | ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ |
| 身份证号(18位) | `^[1-9]\d{5}(19 |
| 中文匹配 | ^[\u4e00-\u9fa5]+$ |
| URL地址 | ^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$ |
| 强密码(8-20位,含大小写+数字+特殊字符) | ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{8,20}$ |
十三、常见误区与避坑指南
- 方括号内的通配符失效:
[.]仅匹配.本身,而非任意字符,方括号内绝大多数元字符无需转义。 - 贪婪与非贪婪混淆:默认贪婪模式会匹配最长结果,提取内容时需用非贪婪模式
.*?避免越界。 - 反向引用规则误解:反向引用的是分组匹配到的内容,而非分组的正则规则。
- 锚点缺失导致校验失效:表单校验时必须加
^和$,否则只要字符串中包含符合规则的片段就会匹配成功,例如\d{6}会匹配abc123456def,而^\d{6}$仅匹配纯6位数字。 - 分支优先级错误:
ab|cd匹配ab或cd,而非a(b|c)d,需用括号限定分支范围。 - 灾难性回溯:嵌套的贪婪量词(如
(a+)*)会导致匹配失败时出现指数级回溯,造成程序卡死,需用原子组、非贪婪模式优化。