正则表达式究竟是什么?一文读懂核心概念
简单来说,正则表达式是一套用于描述字符串匹配规则的“暗号系统”。它能够帮助你在海量文本中快速定位、筛选甚至替换符合特定模式的内容——比如验证手机号、提取邮箱地址、清洗数据中的脏值,这些场景都能轻松应对。在 Python 中操作也非常便捷,只需导入一个 re 库即可开始使用。
三大核心匹配函数:match、search、findall 详解
这三个函数是正则表达式最基础也最常用的工具,我们逐个拆解来看。
1. match():仅在字符串开头进行匹配
- 它从字符串的起始位置开始检查,判断开头是否符合你的规则。
- 如果开头不匹配,直接返回
None,不会继续向后查找。 - 匹配成功则返回一个匹配对象,其中包含匹配的位置和具体内容。
import re
message = '张三、李四、王五、赵六'
result = re.match('张三',message)
print(result)

在这个例子中,“张三”正好位于字符串开头,match() 立刻识别成功。如果换成 match('李四', message) 试试?因为“李四”不在开头,它会直接返回“没找到”。
2. search():扫描整个字符串,找到第一个匹配项
- 它不会死磕开头,而是从头到尾遍历整个字符串,找到第一个符合条件的就停止。
- 无论匹配项藏在哪个位置,只要有一个,就能被捕获。
- 同样返回匹配对象,未找到则返回
None。
import re
message = '张三、李四、王五、赵六'
result = re.search('王五',message)
print(result)

这里“王五”并不在开头,但 search() 依然能把它揪出来——这就是它与 match() 最大的区别。
3. findall():找出所有匹配内容,返回列表
- 它会将整个字符串翻个底朝天,所有符合规则的内容一个不落地全部找出来。
- 返回一个列表,里面包含所有匹配到的子串。
import re
message = '张三、李四、王五、赵六、王五'
result = re.findall('王五',message)
print(result)

正则表达式语法规则速查
掌握函数用法后,关键在于如何编写匹配规则。正则表达式有自己的语法体系,下面挑选最常用的几类进行讲解。
1. 字符范围匹配
[a-z] | 匹配任意一个小写字母 |
[A-Z] | 匹配任意一个大写字母 |
[0-9] | 匹配任意一个数字 |
[a-zA-Z0-9] | 匹配任意一个字母或数字 |
import re
message = 'Python93,C87,Ja va63,C++88'
result_1 = re.search('[cn]',message)
result_2 = re.findall('[0-9]',message)
result_3 = re.findall('[cn][0-9]',message)
print(result_1,result_2,result_3)

2. 匹配次数与位置限定
* | 匹配前面的表达式 0 次或多次 |
+ | 匹配前面的表达式 1 次或多次 |
? | 匹配前面的表达式 0 次或 1 次 |
^ | 匹配输入字符串的开头 |
$ | 匹配输入字符串的结尾 |
{n} | 匹配前面的表达式恰好 n 次 |
{n,} | 匹配前面的表达式至少 n 次 |
{n,m} | 匹配前面的表达式 n 到 m 次 |
import re
message = 'da2a7ddbre77yifed777t3fefd7777b'
result = re.findall('[a-z]*[0-9][a-z]',message)
print(result)

验证手机号码是否合法:
import re
phone_num = input("请输入您的手机号码:")
result = re.findall('^1[0-9]{10}$',phone_num)
print(result)

验证QQ号码是否符合规范:
import re
QQ_num = input("请输入您的QQ号: ")
result = re.match('[1-9][0-9]{4,10}$',QQ_num)
print(result)

验证网站用户名格式:
import re
use_name = input("请输入您的用户名: ")
result = re.findall('^[A-Za-z_]w{7,}$',use_name)
print(result)
import re
use_name = input("请输入您的用户名: ")
result = re.findall('^[A-Za-z_]w{7,}$',use_name)
print(result)

3. 特殊字符与转义序列
d | 匹配一个数字字符,等价于 [0-9] |
D | 匹配一个非数字字符,等价于[^0-9] |
s | 匹配任意空白字符,等价于[fnrtv] |
S | 匹配任何非空白字符,等价于[^fnrtv] |
w | 匹配包括下划线的任何单词字符,等价于 [a-zA-Z0-9_] |
W | 匹配任何非单词字符(不包括下划线),等价于[^A-Za-z0-9_] |
b | 匹配一个单词边界,即单词与空格相邻的位置 |
B | 匹配非单词边界 |
f | 匹配一个换页符 |
n | 匹配一个换行符 |
r | 匹配一个回车符 |
t | 匹配一个制表符 |
v | 匹配一个垂直制表符 |
. | 匹配除 n 和 r 之外的任意单个字符 |
import re message = 'verb very never every' result = re.findall(r'w+erB',message) print(result)

import re
message = 'verb very never every'
result = re.findall('.e',message)
print(result)

贪婪模式与非贪婪模式:匹配量的关键区别
这里有一个容易踩坑的细节:正则表达式默认采用“贪婪”模式——它会尽可能多地匹配字符,只要满足规则就拼命往多了吃。而“非贪婪”模式则相反,一旦满足条件就立刻停止。如何切换?在量词后面加上一个 ? 即可。
import re
message = 'ccc739134792hd'
result = re.findall('cccd+',message)
print(result)
import re
message = 'ccc739134792hd'
result = re.findall('cccd+?',message)
print(result)

或运算与分组:灵活匹配与提取
当你想从一堆数据中筛选出符合多个条件之一的内容时,可以使用“或”运算符。如果你只想提取匹配结果中的某一部分,则需要用到“分组”。
或运算:用 | 符号将两个匹配条件拼接在一起,相当于逻辑“或”。
import re
message = 'verb very never every'
result = re.findall('w+evIw+ry',message)
print(result)

分组:用 (表达式) 将一部分规则包裹起来,匹配成功后,这部分内容会被单独保存到临时区域(一个正则中最多可以存储9个组)。
import re
message = 'verb very never every'
result = re.findall("e(.+)(.)r",message)
print(result)

进阶技能:sub() 替换与 compile() 预编译
除了匹配功能,还有两个非常实用的工具函数能让你的工作流程更加高效。
1. sub():批量替换匹配内容
这个函数可以将字符串中所有符合规则的内容替换成你想要的新字符串,是批量操作的神器。
import re
content = 'dh9322hf9f934hfnf39d'
content = re.sub('d','0',content)
print(content)

2. compile():预编译正则表达式提升性能
如果你需要反复使用同一个正则表达式(比如在循环中),最好先将其预编译成一个模式对象。这样可以节省大量解析时间,显著提升运行效率。
import re
contentl = '2020 12 15 12:00'
pattern = re.compile('d{2}:d{2}')
print(pattern.findall(contentl))

学习正则表达式的小建议
学习正则最忌讳一上来就编写几十行的复杂表达式。几个实用的建议如下:
- 从小例子开始:先练习单个字符、简单数字的匹配,逐步叠加复杂度。
- 多用在线测试工具:例如 Regex101,它能实时显示每一步的匹配结果,调试起来非常直观。
- 别怕记不住:语法确实很多,但常用的就那么几个。写多了自然会刻在脑子里,记不住时翻翻文档就好。
- 先想清楚规律再动手:写之前先分析你要匹配的内容有什么共同特征,比如手机号的位数、邮箱的@符号位置,再将规律转化为表达式。
正则表达式就像一把瑞士军刀,虽然零件多、看起来唬人,但一旦上手,处理字符串的效率会提升一个量级。希望这篇文章能帮你迈过那道门槛。
总结
正则表达式的核心无非是匹配位置、匹配内容和匹配次数。掌握三个基本函数(match、search、findall),学会使用方括号、量词和特殊字符,再理解贪婪与非贪婪的区别,日常处理文本基本够用了。至于替换和预编译等进阶功能,等需求多了自然会去用。慢慢来,别着急。
