正则表达式指南
人生苦短,我用正则。
你有没有过这种体验:看着一串奇形怪状的符号,心里直犯嘀咕——这是在写魔法咒语吗?别怕,那不是巫术,那是正则表达式!虽然它一开始看起来像外星语言,但一旦掌握,你就能轻松驾驭文本世界,像武林高手挥剑断水一样精准又帅气。
今天,让我们带着轻松的心情,一起拆解正则表达式这位“复杂又迷人的老朋友”,顺便吐槽它那些让人又爱又恨的小脾气。
什么是正则表达式?
正则表达式(Regular Expression,简称 RegEx),说白了就是一套用来描述文本模式的神奇符号规则。它能帮你快速找到、匹配、替换文本中的特定内容,效率堪比 Ctrl+F,但姿势更优雅。
想象一下,正则就像一位脾气古怪但超强的猎犬,只要你给出线索(规则),它就能飞速在大海一样的数据里嗅出目标,叼回来给你。
一个小小的栗子 🌰
我们先来看一个最简单的例子,感受一下正则的神奇魅力:
假设你想在一大堆文字中找到所有的数字。正常人:👀肉眼一个个找;程序员:💻正则一把梭!
只需要一条简简单单的正则:
1 | \d |
解释一下:
\d
代表 任意一个数字,也就是 0 到 9 中的任意一个。- 它只匹配一个数字,如果想匹配一串数字,比如身份证号、电话号?加个
+
就行了(后面会讲~)。
比如,在下面这段话里:
今天是 2025 年 4 月 27 日,我喝了 3 杯咖啡。
用正则 \d
,就能快速找到:2、0、2、5、4、2、7、3 —— 简直像开了挂一样!
接下来,我们就要逐步揭秘正则表达式里的更多神器——各种特殊符号和操作符,让你也能用正则秀出风采!🎩✨
基本匹配:一点也不复杂
在正则表达式的世界里,最基础的事情就是:你写啥,它就找啥。
比如:
- 正则
cat
,能在 “I have a cat.” 里找到 cat。 - 正则
dog
,能在 “Hotdog is delicious.” 里找到 dog。
很简单吧?直接对着文字比对,一模一样才能算数。
.
:万物皆可匹配
.
在正则里,代表“任意单个字符”,除了换行符(\n
)之外,其他的通通匹配。
比如:
- 正则
c.t
,可以匹配cat
、cut
、cot
,甚至c9t
,只要中间那个字符存在就行。
.
是个小疯子,什么都要,什么都敢要,记得小心使用!
字符集:你可以自己挑
如果你只想匹配几个特定的字符,可以用方括号 [ ]
包起来,组成一个“字符小团体”。
比如:
[abc]
匹配一个字符,可以是a
、b
或c
。
举例:
- 正则
c[aeiou]t
,可以匹配cat
、cot
、cut
、cet
、cit
,因为中间只允许出现元音字母。
字符集 = 自助餐,随便挑一个吃,不挑别的。
否定字符集:我啥都不要,只要排除他们
在字符集里加个 ^
(插在最前面),就变成了否定字符集,意思是“匹配不在这里面的”。
比如:
[^0-9]
,匹配任何不是数字的字符。[^aeiou]
,匹配任何不是元音字母的字符。
注意:^
只有在方括号 [
后面立刻出现时,才表示否定!放在外面那是另一个意思了!(后面讲)
字母范围 & 数字范围:别傻傻一个个列
如果你想匹配从 a
到 z
所有小写字母,或者从 0
到 9
所有数字,可以用范围表达,省事儿。
格式就是用一个短横线 -
连起来:
[a-z]
:匹配任意小写字母。[A-Z]
:匹配任意大写字母。[0-9]
:匹配任意数字。
当然你也可以组合:
[a-zA-Z0-9]
:匹配所有字母和数字,走到哪儿都好用的万金油组合。
重复匹配:*、?、+、{}的华丽登场
匹配一个字符?太单调了!
匹配很多个字符?这才叫快乐!
正则提供了一套“量词”,让你可以控制“匹配多少次”。
*
:0次或者多次
*
表示前面的东西可以出现 零次、一次或者多次,想来多少来多少。
比如:
- 正则
go*gle
可以匹配:- `ggle`(一个 `o` 都没有) - `gogle` - `gooogle` - `goooooooogle`
*
是一位极度包容的老好人,不来可以,来一大堆也没问题。
?
:要来就来一个,不来也行
?
表示前面的东西可以出现 零次或一次,要么有,要么没有,别太贪心。
比如:
- 正则
colou?r
可以匹配:color
colour
英式拼法美式拼法?一个 u
搞定!
+
:至少来一个,别想偷懒
+
表示前面的东西必须出现 至少一次,一次以上没上限。
比如:
- 正则
lo+l
可以匹配:lol
loool
looooooooool
但不能匹配只有 ll
的情况,因为中间必须有至少一个 o
。
{}
:精准打击选手
如果你想精确地控制出现的次数,可以用花括号 {}
:
{n}
:正好 n 次{n,}
:至少 n 次{n,m}
:至少 n 次,最多 m 次
比如:
\d{4}
匹配恰好四位数字,比如年份2025
。\d{2,4}
匹配2到4位数字,比如23
、202
、2025
。
这种写法就像开精准制导导弹,目标明确,打击到位!
🎯 小结:
*
:可以啥都没有,或者来一堆。?
:可有可无,没啥强制要求。+
:必须有一个起步。{}
:想来几次,咱自己说了算!
分组玩法:组织一下,世界更美好
正则表达式虽然自由,但自由久了容易乱套。所以,分组 ()
机制就诞生了:把一段东西抱在一起,作为一个整体来处理。
就像开会拉个小组讨论,大家更有组织感!
()
:普通分组
普通的圆括号 ()
有两个作用:
- 把内容打包成一个整体。比如你想重复一整块内容,就可以打包起来再用
*
、+
等量词。 - 捕获匹配的内容。也就是可以把匹配到的小块内容拿出来以后用。
比如:
- 正则
(ab)+
可以匹配:ab
abab
ababab
每次匹配的是整个 ab
,而不是单独的 a
或 b
。
捕获的内容也可以在替换文本时用,比如 \1
代表第一个括号里的内容,超实用!(后面举例)
(?:)
:非捕获分组
有时候你只是想分个组,方便管理,但你压根不想“捕获”它。
这时就用 (?:...)
—— 非捕获分组!
比如:
- 正则
(?:cat|dog)+
会匹配:cat
dog
catdogcat
但不会单独记录是哪个子串,纯粹为了逻辑清晰,不留证据,不搞记录。
总结:
()
:分组 + 捕获(?:)
:分组,不捕获,低调做人。
其他好用的家伙们:|、转义符、^、$
到了这里,正则的武器库里还剩下一些必学技能,咱们逐个拿出来摆一摆!
|
:二选一?多选一!
竖线 |
表示或者(OR)。
比如:
- 正则
cat|dog
可以匹配cat
或dog
,有点像语文里的“选择题”。
配合括号使用效果更佳,比如:
(cat|dog|fish)
,这回是猫猫狗狗加小鱼干,三选一!
转义字符:想用特殊符号?加个 \
有些符号在正则里本来是有特殊意义的,比如 .
, *
, ?
, +
, (
, )
, [
, ]
, {
, }
, |
, ^
, $
,它们都有各自的小性格。
如果你就是想字面上匹配这些符号,就要在前面加个 \
,转义它!
比如:
\.
匹配真正的句点.
\*
匹配真正的星号*
\\
匹配一个反斜杠\
(因为反斜杠自己也需要转义,懂得都懂)
总之:遇到叛逆符号,加个 \
驯服它!
^
:开头对线
^
有两种用法(别跟字符集里的 [^ ]
搞混!)
在正则开头,^
表示字符串的开始。
比如:
- 正则
^Hello
只会匹配以Hello
开头的字符串,比如:- ✅
Hello world!
- ❌
Say Hello!
(因为Hello
不在开头)
- ✅
小提醒:^
是个很讲原则的人,只在最开头严格守岗。
$
:结尾封印
$
表示字符串的结束。
比如:
- 正则
world!$
只会匹配以world!
结尾的字符串,比如:- ✅
Hello world!
- ❌
Welcome to the world! Hello
(虽然有world!
,但不是结尾)
- ✅
如果你又用了 ^
又用了 $
,比如:
^abc$
就要求整个字符串只能是abc
,中间不允许有多余的字符,超严格!
🎯 小结:
|
:你选我或者选我或者选我。\
:乖,别皮,给你加个转义。^
:我只看开头。$
:我只守结尾。
常见特殊字符:懒人速记宝典
如果你觉得 [a-zA-Z0-9_]
写起来太麻烦,别急,正则贴心地给了你一些懒人专用的速记字符,直接一招搞定!
\w
和 \W
:字母数字下划线 vs 非字母数字下划线
\w
:匹配字母、数字和下划线(等价于[a-zA-Z0-9_]
)\W
:匹配不是字母、数字、下划线的字符(就是\w
的反面)
比如:
- 正则
\w+
可以匹配单词、用户名、变量名,比如hello_123
。 - 正则
\W
可以匹配空格、标点符号、表情包(?)这种奇奇怪怪的玩意儿。
\s
和 \S
:空白字符 vs 非空白字符
\s
:匹配所有空白字符(空格、Tab、换行、回车……)\S
:匹配所有非空白字符
比如:
- 正则
\s+
可以用来找出一大堆空格,比如排版时顺手清理掉那些乱飞的空格怪。 - 正则
\S+
可以快速找到连续的非空白内容,比如提取一整段话。
\d
和 \D
:数字 vs 非数字
\d
:匹配数字(0到9)\D
:匹配非数字的任何东西
比如:
- 正则
\d{3}-\d{4}
可以匹配一个形如123-4567
的电话号码后缀。 - 正则
\D+
则可以找到连绵不断的字母、符号、奇奇怪怪的文本串。
🎯 小结:
| 速记符号 | 匹配的内容 |
| :———: | :———————————: |
| \w
| 字母、数字、下划线 |
| \W
| 非字母、非数字、非下划线 |
| \s
| 空白字符 |
| \S
| 非空白字符 |
| \d
| 数字 |
| \D
| 非数字 |
零宽断言:窥视未来,不留下脚印
来到高阶正则技巧——零宽断言!(又称“零宽度匹配”)
它们神奇地做到:检查某个条件是否成立,但不真正消费任何字符。就像一个隐身侦察兵,观察后留下一片寂静。
主要有四种:
正向先行断言(Positive Lookahead)
格式:X(?=Y)
意思是:匹配 X
,只有在它后面紧跟着 Y
时才算成功,但是匹配结果只包含X,不包括Y。
比如:
- 正则
\d+(?=元)
可以匹配100
(在字符串 “100元” 中),但只提取100
,不会把元
算进去。
简单理解:我要X,但我得偷偷瞄一眼它后面是不是Y。
负向先行断言(Negative Lookahead)
格式:X(?!Y)
意思是:匹配 X
,只有在它后面 不是Y 的情况下才算成功。
比如:
- 正则
foo(?!bar)
可以匹配foo
,但只在后面不是bar
的情况下。
简单理解:我要X,但后面不能跟着那个讨厌的Y。
正向后行断言(Positive Lookbehind)
格式:(?<=Y)X
意思是:匹配 X
,前面必须是Y,但只捕获X。
比如:
- 正则
(?<=\$)\d+
可以匹配 “$100” 中的100
,只要前面有个$
符号就行。
简单理解:只有在Y后面出生的X,我才要。
负向后行断言(Negative Lookbehind)
格式:(?<!Y)X
意思是:匹配 X
,前面不能是Y。
比如:
- 正则
(?<!\$)\d+
可以匹配没有$
符号标记的钱数,比如找出纯数字的价格。
简单理解:只要前面不是Y,X就自由飞翔!
🎯 小结版对比表:
名称 | 方向 | 要求 | 例子(匹配部分) |
---|---|---|---|
正向先行断言 | 后看 | 必须有Y | \d+(?=元) |
负向先行断言 | 后看 | 不能有Y | foo(?!bar) |
正向后行断言 | 前看 | 必须有Y | (?<=\$)\d+ |
负向后行断言 | 前看 | 不能有Y | (?<!\$)\d+ |
小结一句话总结:
零宽断言,就是悄悄打量,不打扰,验身份,不占地方。
正则标志:戴上不同的眼镜看世界
写正则时,我们可以加一些标志(Flags),就像给正则戴上一副魔法眼镜,立刻改变它的行为方式!
这些标志通常写在正则外面,比如 /pattern/flags
,不同语言的写法略有差异,但灵魂是一致的!
g
:全局匹配(global)
默认情况下,正则只会找到第一个匹配就停下(就像只抓到一条鱼就不钓了)。
加上 g
标志,正则就会一路狂奔,找到所有符合的匹配!
比如:
- 正则
/cat/g
在字符串"cat dog cat"
中会匹配两次cat
。
简单理解:带上 g
,战斗到最后一兵一卒!
i
:忽略大小写(ignore case)
有些时候,大小写不重要,做人要宽容,匹配也一样。
加上 i
标志,正则就不区分大小写了!
比如:
- 正则
/hello/i
可以匹配Hello
、HELLO
、hElLo
……
简单理解:我不在乎你是大写小写,心灵契合才是王道。
m
:多行模式(multiline)
默认情况下,^
和 $
只匹配整串文本的开头和结尾。
加上 m
标志,^
匹配每一行的开头,$
匹配每一行的结尾!
比如:
文本是:helloworld
正则
/^world/m
可以匹配到world
,因为现在每一行都有自己的“起点”了。
简单理解:每一行,都值得被认真对待!
🎯 小结:
标志 | 作用 |
---|---|
g |
全局匹配,找到所有匹配 |
i |
忽略大小写匹配 |
m |
多行模式,行行高亮 |
小提醒:
有些语言(比如 Python 的 re
模块)用 re.IGNORECASE
、re.MULTILINE
这样写,但道理是一样的!
贪婪与非贪婪匹配:吃多少,够就好
正则界的量词(比如 *
、+
、{}
)默认是贪婪的,也就是说:
能吃多少,就吃多少!
但有时候,我们想要它矜持一点,只吃够的那一口,不要狼吞虎咽。
这时候,就要使用非贪婪匹配(也叫懒惰匹配,Lazy)。
贪婪匹配:能吃绝不剩!
默认的贪婪量词:
*
:匹配 0 次或多次(尽可能多)+
:匹配 1 次或多次(尽可能多){n,m}
:匹配 n 到 m 次(尽可能多)
比如:
- 正则
<.*>
匹配"hello <b>world</b> text"
会得到<b>world</b>
,而不是<b>
。
因为.*
太贪婪了,一口气吃到了最后一个>
!
非贪婪匹配:适可而止
在量词后面加一个 ?
,就变成了非贪婪量词!
*?
:匹配 0 次或多次(尽可能少)+?
:匹配 1 次或多次(尽可能少){n,m}?
:匹配 n 到 m 次(尽可能少)
比如:
- 正则
<.*?>
匹配"hello <b>world</b> text"
会得到<b>
,
因为.*?
只吃到遇到第一个>
为止,超有分寸!
🎯 贪婪 vs 非贪婪 简明对比:
匹配方式 | 表达式 | 行为 |
---|---|---|
贪婪匹配 | <.*> |
尽可能多,吃到最后一个 > |
非贪婪匹配 | <.*?> |
尽可能少,遇到第一个 > 就收手 |
小总结一句话:
贪婪匹配:全世界我都要!
非贪婪匹配:遇到就好,不强求~
写在最后:正则之路,刚刚开始!
恭喜你一路披荆斩棘,走到这里!
如果你认真看完了这篇正则表达式指南,那么恭喜你,已经比绝大多数程序员更懂正则了!(没开玩笑)
当然,正则表达式就像一门武功,只看不练,是学不会六脉神剑的。
真正的掌握,需要多敲、多练、多踩坑、多吐槽。
为了让你快速升级打怪,我特别推荐一个超棒的网站:
这个网站简直就是正则界的小甜品店!
- 每一课短小精悍,轻松易懂
- 支持中文界面,不用翻词典
- 在线就能练习,做题刷经验
- 还能直接看到匹配效果,快乐加倍!
最后,送你一句话作为结尾:
正则表达式不是魔法,它只是复杂得像魔法而已。
慢慢来,哪怕今天只学会了一个.
,也已经比昨天更强啦!
(完)