在真实的数据分析项目中,原始数据往往"脏乱差"------包含大量非结构化文本,如用户评论、日志、网页抓取内容等。如何从中精准提取电话号码、邮箱、日期、金额等关键信息?答案就是:正则表达式(Regular Expression)。
Python 通过标准库 re 提供了强大而灵活的正则支持。本文将系统讲解正则在数据分析中的核心用法,涵盖:
- 字符串匹配函数(
match、search、findall) - 正则语法(字符范围、重复次数、字符类)
- 贪婪与非贪婪模式
- 分组与逻辑"或"
- 替换与编译优化(
sub、compile)
一、匹配字符串:三大核心函数
1. re.match():从字符串开头匹配
- 作用 :仅检查字符串起始位置是否匹配正则模式。
- 返回值 :匹配成功返回
Match对象,否则None。
使用形式:
python
re.match(参数1,参数2)
**功能:**表示从参数2(字符串类型数据)中查找满足参数1(正则表达式)的内容。
实例代码:
python
import re
messaga = '张三、李四、王五、赵六、张三'
result = re.match('张三', messaga)
print(result)
result1 = re.match('李四', messaga)
print(result1)
代码执行结果:

- span=(0,2)表示字符串索引号为0~2的位置匹配成功。
- match='张三'表示匹配的内容为张三。
2. re.search():全文搜索首次匹配
- 作用 :在整个字符串中查找第一个匹配项。
- 返回值 :首个匹配的
Match对象,或None。
使用形式:
python
re.search(参数1,参数2)
**功能:**表示从参数2(字符串类型数据)中查找满足参数1(正则表达式)的内容,如果匹配了多个参数1,则只返回第一个匹配成功的信息。
示例代码:
python
messaga1 = '张三、李四、王五、赵六、王五'
result2 = re.search('王五', messaga1)
print(result2)
代码执行结果:

只返回第一个匹配成功的信息。
3. re.findall():查找所有匹配项
- 作用 :返回所有非重叠匹配结果的列表。
- 返回值:字符串列表(若无分组);元组列表(若有多个分组)。
使用形式:
python
re.findall(参数1,参数2)
功能:表示从参数2(字符串类型数据)中查找满足参数1(正则表达式)的内容,如果匹配了多个参数1,则返回匹配成功的全部信息。
python
import re
messaga1 = '张三、李四、王五、赵六、王五'
result3 = re.findall('王五', messaga1)
print(result3)
运行结果:
['王五','王五']
findall()并不返回匹配的位置,只返回匹配的全部内容。
二、正则表达式基础语法
表示字符范围:[...]
用方括号定义可接受的字符集合:
| 表达式 | 含义 |
|---|---|
[abc] |
匹配 a、b 或 c |
[a-z] |
匹配任意小写字母 |
[0-9] |
等价于 \d,匹配数字 |
[^0-9] |
取反,匹配非数字字符 |
示例:
python
import re
message = 'Pythonnnnncc93,c87,Javac63,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)
print(result_2)
print(result_3)
运行结果:

表示字符出现的次数(量词)
| 符号 | 含义 | 示例 |
|---|---|---|
* |
0 次或多次 | ab* → "a", "ab", "abb" |
+ |
1 次或多次 | \d+ → 至少一个数字 |
? |
0 次或 1 次 | colou?r → "color" / "colour" |
{n} |
恰好 n 次 | \d{4} → 四位年份 |
{n,} |
至少 n 次 | \d{3,} → 三位及以上数字 |
{n,m} |
n 到 m 次 | \d{2,4} → 2~4 位数字 |
示例:
python
import re
message1 = 'da2a7ddbre77yifed777t3fefd777b'
result = re.findall('[a-z]*[0-9][a-z]', message1)
print(result)
运行结果:

表示同一类字符(预定义字符类)
| 符号 | 等价写法 | 含义 |
|---|---|---|
\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] |
非空白字符 |
\b |
单词边界,即单词中与空格邻接的字符 | |
\B |
非单词边界 | |
\f |
分页符 | |
\n |
换行符 | |
\r |
回车符 | |
\t |
制表符 | |
\v |
垂直制表符 | |
.: |
匹配除"\n"和"\r"之外的任何单个字符 |
示例:清洗文本中的非字母数字字符
python
import re
text = "Hello, World! 123 @#$"
clean = re.sub(r"\W", " ", text) # \W = 非单词字符
print(clean) # "Hello World 123 "
三、贪婪模式 vs 非贪婪模式
贪婪和非贪婪模式指是否匹配更多内容,具体使用如下:
- 默认是贪婪模式:尽可能多地匹配字符。
- 非贪婪(惰性)模式 :在量词后加
?,尽可能少匹配。
python
text = "<div>Hello</div><div>World</div>"
# 贪婪:匹配整个字符串
print(re.search(r"<div>.*</div>", text).group())
# 输出:<div>Hello</div><div>World</div>
# 非贪婪:只匹配第一个标签
print(re.search(r"<div>.*?</div>", text).group())
# 输出:<div>Hello</div>
数据分析提示:提取 HTML/XML 标签、JSON 片段时,务必使用非贪婪模式!
四、 "或" 和 分组(Grouping)
逻辑"或":|
python
re.findall(r"jpg|png|gif", "image1.jpg, image2.png, icon.gif")
# 输出:['jpg', 'png', 'gif']
分组:(...) 与捕获
用括号将模式分组,便于提取子内容:
python
date_str = "2025-04-05"
match = re.search(r"(\d{4})-(\d{2})-(\d{2})", date_str)
print(match.groups()) # ('2025', '04', '05')
print(match.group(1)) # '2025'(年)
五、sub() 和 compile() 方法
re.sub():替换匹配内容
- 作用:将匹配到的文本替换为指定字符串。
- 语法 :
re.sub(pattern, repl, string)
python
import re
text = "Call me at 138****5678"
cleaned = re.sub(r"\d{3}\*\*\*\d{4}", "[PHONE_HIDDEN]", text)
print(cleaned) # Call me at [PHONE_HIDDEN]
支持使用分组引用(\1, \2):
python
import re
text = "John Doe"
swapped = re.sub(r"(\w+) (\w+)", r"\2, \1", text)
print(swapped) # Doe, John
re.compile():预编译正则(提升性能)
当同一正则需多次使用(如处理百万行数据),应先编译:
python
phone_pattern = re.compile(r"1[3-9]\d{9}")
# 后续可直接调用
if phone_pattern.search(text1):
...
if phone_pattern.findall(text2):
...
综合案例:
给定字符串 log_info = "用户ID:10086,订单号:ORD20260122001,支付金额:99.9元;用户ID:10087,订单号:ORD20260122002,支付金额:199.5元;用户ID:10088,订单号:ORD20260122003,支付金额:0.88元"
1、基础匹配:提取所有的用户 ID 数字(如 10086、10087、10088),并以列表形式输出。
2、捕获组 + 贪婪 / 非贪婪:提取所有的订单号(如 ORD20260122001),要求分别用贪婪匹配和非贪婪匹配实现,并对比两种方式的结果(思考为什么结果一致 / 不一致)。
3、数值提取:提取所有的支付金额数字(仅保留数字部分,如 99.9、199.5、0.88),忽略 "元" 字,最终输出浮点数列表。
实现代码:
python
import re
log_info = "用户ID:10086,订单号:ORD20260122001,支付金额:99.9元;用户ID:10087,订单号:ORD20260122002,支付金额:199.5元;用户ID:10088,订单号:ORD20260122003,支付金额:0.88元"
pattern1 = re.compile(':(\d+),')
print(pattern1.findall(log_info))
pattern2 = re.compile('ORD\d+') # 贪婪模式
print(pattern2.findall(log_info))
pattern3 = re.compile('ORD2026012200\d+?') # 非贪婪模式
print(pattern3.findall(log_info))
pattern4 = re.compile(':(\d+.\d+)元')
print(pattern4.findall(log_info))
结语
记住口诀:
- 提取一个用
search,- 提取多个用
findall,- 替换内容用
sub,- 高频使用要
compile!