Python中正则表达式从入门到精通详解(这一篇就够了!)

 更新时间:2026年06月24日 10:42:51   作者:zzwq.  
正则表达式是每一位开发者必须掌握的文本处理利器,它能以简洁语法高效完成复杂匹配任务,这篇文章主要介绍了Python中正则表达式从入门到精通的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、正则表达式是什么?

1.1 一个生活化的理解

想象一下,你在一个巨大的图书馆里,想找所有书名中包含Python的书。如果一本本翻,你可能要花上一整天。但如果你有一个魔法探测器,只要输入Python这个关键词,所有相关书籍就会自动跳出来——这就是正则表达式的工作原理!

正则表达式(Regular Expression,简称regex)是一种用于描述字符串模式的特殊语法。它使用一系列特殊字符和普通字符来定义一种模式,然后用这种模式去匹配、查找、替换或分割文本。简单来说,正则表达式就是一套文本搜索的规则,告诉你想要找什么样的字符串。

1.2 正则表达式能做什么?

正则表达式在文本处理领域可谓是全能选手,主要可以解决四类问题:

  • 校验文本内容:验证用户输入的手机号、邮箱格式是否正确
  • 提取文本内容:从一堆杂乱文本中抓取你想要的信息
  • 替换文本内容:批量修改文本中的某些模式
  • 切割文本内容:按照特定规则拆分字符串

比如,你可以在几万行日志中快速找到所有报错的时间戳,或者将文档中的所有日期格式从“2026/01/01”批量替换为“2026-01-01”。

1.3 开始前的准备

在Python中使用正则表达式,首先需要导入内置的re模块:

import re

建议在编写正则表达式时使用原生字符串(即在字符串前加r),这样可以避免转义字符带来的麻烦:

python
# 推荐写法
pattern = r'\d+'  # 匹配数字

# 不推荐(虽然也能用)
pattern = '\\d+'

二、正则表达式基础语法

正则表达式的核心是一套“元字符”——这些字符在正则表达式中有着特殊含义,而不是代表它们本身的样子。掌握下面这些常用语法,足以应对大多数日常使用场景。

2.1 元字符详解

元字符含义示例匹配结果
.匹配除换行符以外的任意单个字符a.baab、a5b、a b
^匹配字符串开头Hello以Hello开头的字符串
$匹配字符串结尾world$以world结尾的字符串
*匹配前面的子表达式0次或多次ab*cac、abc、abbc
+匹配前面的子表达式1次或多次ab+cabc、abbc(不匹配ac)
?匹配前面的子表达式0次或1次colou?rcolor、colour
{n}匹配前面的子表达式恰好n次a{3}aaa
{n,m}匹配前面的子表达式至少n次,最多m次a{2,4}aa、aaa、aaaa
[ ]字符集合,匹配括号内任意一个字符[abc]a、b或c中的任意一个
[^]负值字符集合,匹配未包含的任意字符[^abc]除了a、b、c之外的任何字符
|或运算符cat\|dogcat或dog
()分组标记(ab)+ab、abab
\转义字符\.匹配句点.本身

2.2 预定义字符集(简化写法)

正则提供了一些预定义的字符集,可以大大简化表达式的书写:

预定义字符等价写法含义
\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    —单词边界(匹配单词开头或结尾)

举个例子:

\d+ 表示匹配一个或多个连续的数字(比如提取文本中的所有数字)
\w+ 表示匹配一个或多个单词字符(比如提取英文单词)
\s+ 表示匹配一个或多个空白字符(比如用来分割字符串)

2.3 理解“贪婪”与“非贪婪”

贪婪匹配:默认情况下,正则表达式会尽可能多地匹配字符。比如正则<.*>匹配字符串<div>hello</div>时,会匹配整个<div>hello</div>,而不是只匹配<div>。

非贪婪匹配:在量词后面加一个?,就会变成非贪婪模式,尽可能少地匹配字符。比如<.*?>只会匹配<div>。

python
import re

text = '<div>hello</div><p>world</p>'

# 贪婪匹配(默认)——匹配尽可能长的结果
print(re.findall(r'<.*>', text))
# 输出: ['<div>hello</div><p>world</p>']

# 非贪婪匹配(加 ?)——匹配尽可能短的结果
print(re.findall(r'<.*?>', text))
# 输出: ['<div>', '</div>', '<p>', '</p>']

非贪婪模式在处理HTML标签、引号内的内容时非常有用。

三、re模块常用函数

Python的re模块提供了丰富的函数来处理正则表达式。

3.1 re.match()——从头开始匹配

re.match()从字符串的起始位置开始匹配,如果开头不符合规则就返回None。

python
import re

# match要求从开头就匹配
result = re.match(r'\d+', '123abc456')
if result:
    print(result.group())  # 输出: 123

# 开头不匹配,返回None
result = re.match(r'\d+', 'abc123')
print(result)  # 输出: None

3.2 re.search()——搜索第一个匹配

re.search()在整个字符串中搜索,返回第一个匹配到的结果。

python
import re

# search在整个字符串中查找
result = re.search(r'\d+', 'abc123def456')
if result:
    print(result.group())  # 输出: 123(只返回第一个)

match()和search()的区别在于:match()必须从字符串开头匹配,search()可以在任何位置查找。

3.3  re.findall()——找出所有匹配 (最常用)

re.findall()返回字符串中所有不重叠匹配项的列表,是日常使用最频繁的函数。

python
import re

text = '我有3个苹果,5个香蕉,8个橙子'
# 找出所有数字
numbers = re.findall(r'\d+', text)
print(numbers)  # 输出: ['3', '5', '8']

# 找邮箱
text2 = '联系我: test@example.com 或 support@python.org'
emails = re.findall(r'\w+@\w+\.\w+', text2)
print(emails)  # 输出: ['test@example.com', 'support@python.org']

3.4 re.finditer()——逐个获取匹配对象

当需要处理大量匹配结果时,finditer()返回一个迭代器,每个元素是Match对象,比findall()更节省内存。

python
import re

text = '价格: 100元, 200元, 300元'
for match in re.finditer(r'\d+', text):
    print(f'找到数字: {match.group()},位置: {match.span()}')
# 输出:
# 找到数字: 100,位置: (4, 7)
# 找到数字: 200,位置: (9, 12)
# 找到数字: 300,位置: (14, 17)

3.5  re.sub()——替换文本

re.sub()用于替换字符串中匹配模式的部分,是批量处理文本的利器。

python
import re

# 将数字替换为 #
result = re.sub(r'\d+', '#', '房间123,楼层4')
print(result)  # 输出: 房间#,楼层#

# 移除所有空白字符
text = 'abc 12\ de 23 \n f45 6'
cleaned = re.sub(r'\s+', '', text)
print(cleaned)  # 输出: abc12de23f456

3.6  re.split()——按模式分割

re.split()按照匹配模式分割字符串,返回一个列表。

python
import re

# 按数字分割字符串
text = 'abc123def456ghi'
parts = re.split(r'\d+', text)
print(parts)  # 输出: ['abc', 'def', 'ghi']

# 按多种分隔符分割
text2 = 'apple, banana; orange|grape'
result = re.split(r'[,;|]', text2)
print(result)  # 输出: ['apple', ' banana', ' orange', 'grape']

3.7  re.compile()——编译正则表达式

如果在程序中多次使用同一个正则表达式,可以将其编译成一个Pattern对象,这样可以提高效率。

python
import re

# 编译正则表达式
pattern = re.compile(r'\d+')

# 然后就可以反复使用这个pattern对象了
text1 = '我有10个苹果'
text2 = '他有20个橙子'

print(pattern.findall(text1))  # ['10']
print(pattern.search(text2).group())  # 20
print(pattern.sub('#', '价格123元'))  # 价格#元

四、分组与捕获

4.1 基础分组:用 () 提取关键内容

分组是正则表达式中最强大的功能之一。用圆括号将想要单独获取的部分括起来,匹配成功后就可以通过.group(1)、.group(2)等提取出来。

python
import re

# 提取电话号码的区号和号码
text = '我的电话是010-12345678'
pattern = r'(\d{3})-(\d{8})'

match = re.search(pattern, text)
if match:
    print(f'区号: {match.group(1)}')   # 输出: 010
    print(f'号码: {match.group(2)}')   # 输出: 12345678
    print(f'完整匹配: {match.group(0)}') # 输出: 010-12345678
    print(f'所有分组: {match.groups()}') # 输出: ('010', '12345678')

4.2 非捕获分组 (?:...)

有些时候我们只需要分组功能来应用量词,但不需要提取这部分内容,这时可以使用非捕获分组(?:...)。非捕获分组不会占用分组编号,性能也更高。

python
import re

# 非捕获分组:只分组不捕获
pattern = r'(?:https?://)?(\w+\.\w+)'
text = '访问 https://example.com 和 http://python.org'

matches = re.findall(pattern, text)
print(matches)  # 输出: ['example.com', 'python.org']

4.3 命名分组 (?P<name>...)

当分组较多时,用数字编号group(1)、group(2)很容易搞混。命名分组可以给每个分组起一个名字,大大提升代码的可读性。

python
import re

# 命名分组:使用 (?P<名字>模式) 的格式
pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
text = '今天是2025-03-15'

match = re.search(pattern, text)
if match:
    print(f'年: {match.group("year")}')   # 输出: 2025
    print(f'月: {match.group("month")}')  # 输出: 03
    print(f'日: {match.group("day")}')    # 输出: 15
    print(f'所有命名分组: {match.groupdict()}')
    # 输出: {'year': '2025', 'month': '03', 'day': '15'}

4.4 反向引用 \1、\2 等

反向引用允许在同一个正则表达式中引用前面捕获组的内容,常用于匹配重复的结构。

python
import re

# 匹配重复的单词(如 "hello hello")
pattern = r'\b(\w+)\s+\1\b'
print(re.search(pattern, 'hello world'))    # 输出: None(不匹配)
print(re.search(pattern, 'hello hello'))    # 输出: 匹配成功
print(re.search(pattern, 'good good study')) # 输出: 匹配成功(good good)

五、进阶技巧

5.1 零宽断言——精准定位的秘密武器

零宽断言是一种不消耗字符的匹配方式,它只判断位置是否符合条件,而不把判断用的字符包含在匹配结果中。简单来说,就是“我要求前面/后面有什么(或没什么),但我不把它拿走”。

四种断言类型:

断言类型语法含义
正向先行断言(?=...)匹配后面是指定内容的位置
负向先行断言(?!...)匹配后面不是指定内容的位置
正向后行断言(?<=...)匹配前面是指定内容的位置
负向后行断言(?<!...)匹配前面不是指定内容的位置

实战示例:

python
import re

# 示例1:提取美元符号后面的数字(正向后行断言)
text = '售价¥299,促销价$199'
pattern = r'(?<=\$)\d+'  # 匹配 $ 后面的数字,但 $ 不包含在结果中
print(re.findall(pattern, text))  # 输出: ['199']

# 示例2:排除jpg/png文件(负向先行断言)
files = 'image.jpg backup.zip config.yaml'
pattern = r'\b\w+\.(?!jpg|png)\w{3}\b'  # 匹配不是jpg/png结尾的文件
print(re.findall(pattern, files))  # 输出: ['backup.zip', 'config.yaml']

# 示例3:提取中括号内的内容(前后配合)
log = 'ERROR [2026-01-01] 系统崩溃'
pattern = r'(?<=\[).+?(?=\])'  # 匹配 [ 和 ] 之间的内容
print(re.search(pattern, log).group())  # 输出: 2026-01-01

5.2 贪婪与非贪婪再深入

前面我们简单介绍了贪婪和非贪婪,这里再补充一些优化建议:

  • 当匹配引号内的内容时,"(.+?)" 虽然能用,但每次遇到引号都要尝试回溯。更好的写法是 "([^"]*)",直接用否定字符集匹配到下一个引号,避免了回溯尝试。
  • 在量词后面加?即可变成非贪婪模式:*?、+?、{n,m}?、??。

5.3 性能优化建议

如果处理的是大规模文本,正则表达式的性能就变得至关重要:

1. 预编译正则表达式:对于重复使用的模式,使用re.compile()编译成Pattern对象
2. 避免灾难性回溯:不要使用(a+)+这类嵌套量词,会导致指数级回溯
3. 用字符类替代点号:[^"]* 比 .*? 更高效
4. 使用锚点:^ 和 $ 能帮助正则引擎快速定位,减少搜索范围
5. 先用简单方法过滤:对于大规模文本,先用 in 操作符或 startswith() 粗略筛选,再用正则精确匹配。

六、实战案例

6.1 提取中文字符

python
import re

text = 'Python正则表达式入门教程123'
# 匹配中文字符(基本汉字范围)
chinese = re.findall(r'[\u4e00-\u9fff]+', text)
print(chinese)  # 输出: ['正则表达式入门教程']

6.2 验证手机号码

python
import re

def is_valid_phone(phone):
    pattern = r'^1[3-9]\d{9}$'  # 11位数字,以1开头,第二位是3-9
    return bool(re.match(pattern, phone))

print(is_valid_phone('13812345678'))  # True
print(is_valid_phone('12345678901'))  # False

6.3 提取邮箱地址

python
import re

text = '请联系我: test.user@example.com 或 admin@python.org'
pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
emails = re.findall(pattern, text)
print(emails)  # 输出: ['test.user@example.com', 'admin@python.org']

6.4 数据清洗——去除HTML标签

python
import re

html = '<div class="content"><p>欢迎来到<span>Python</span>世界!</p></div>'
# 去除所有HTML标签
clean_text = re.sub(r'<[^>]+>', '', html)
print(clean_text)  # 输出: 欢迎来到Python世界!

6.5 日志解析实战

python
import re

log = '''
2026-04-06 19:23:45 INFO 用户登录成功
2026-04-06 19:25:12 ERROR 数据库连接失败
2026-04-06 19:30:08 WARN 响应时间过长
'''

# 提取所有错误日志的时间和信息
pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ERROR (.+)'
errors = re.findall(pattern, log)
for time, msg in errors:
    print(f'错误发生时间: {time}, 错误信息: {msg}')
# 输出: 错误发生时间: 2026-04-06 19:25:12, 错误信息: 数据库连接失败

七、常见错误与避坑指南

错误1:忘记使用原生字符串

python
# 错误写法
pattern = '\d+'  # 这里 \d 可能被Python解释器当作转义序列处理

# 正确写法
pattern = r'\d+'  # 使用原生字符串

错误2:混淆 match 和 search

python
# re.match() 要求从开头匹配
re.match(r'\d+', 'abc123')  # 返回 None

# re.search() 可以在任何位置查找
re.search(r'\d+', 'abc123')  # 返回匹配对象

错误3:分组编号理解错误

分组编号是按照左括号出现的顺序来确定的,而不是按照层级。例如在((A)(B))C中,组1是((A)(B)),组2是(A),组3是(B)。

错误4:正则表达式写得太复杂

正则表达式并非越复杂越好。如果模式极其复杂(比如完整匹配URL或邮箱的“完美”正则),建议用专门的库来处理,而不是试图用一个正则解决所有问题。保持简洁和可维护性更重要。

总结

到此这篇关于Python中正则表达式从入门到精通的文章就介绍到这了,更多相关Python正则表达式详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python2手动安装更新pip过程实例解析

    Python2手动安装更新pip过程实例解析

    这篇文章主要介绍了Python2手动安装更新pip过程实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • PyInstaller的安装和使用的详细步骤

    PyInstaller的安装和使用的详细步骤

    这篇文章主要介绍了PyInstaller的安装和使用的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • python openCV自制绘画板

    python openCV自制绘画板

    这篇文章主要为大家详细介绍了python openCV自制绘画板,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-10-10
  • windows下添加Python环境变量的方法汇总

    windows下添加Python环境变量的方法汇总

    默认情况下,在windows下安装python之后,系统并不会自动添加相应的环境变量。此时不能在命令行直接使用python命令。今天我们就来看下,如何简单快捷的在windows下添加Python环境变量
    2018-05-05
  • flask + pymysql操作Mysql数据库的实例

    flask + pymysql操作Mysql数据库的实例

    下面小编就为大家带来一篇flask + pymysql操作Mysql数据库的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • Python的Flask框架的简介和安装方法

    Python的Flask框架的简介和安装方法

    这篇文章主要介绍了Python的Flask框架的简介和安装方法,Flask是一款高人气的非常简洁的web开发框架,需要的朋友可以参考下
    2015-11-11
  • Python利用Pydub实现自动分割音频

    Python利用Pydub实现自动分割音频

    pydub是一个轻量级的音频处理库,安装方便,使用简单。而且pydub提供了丰富的音频处理功能,包括切割、合并、转换等。本文将利用Pydub实现自动分割音频功能,感兴趣的可以了解一下
    2023-05-05
  • python之MSE、MAE、RMSE的使用

    python之MSE、MAE、RMSE的使用

    今天小编就为大家分享一篇python之MSE、MAE、RMSE的使用,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-02-02
  • Python数据类型探索列表魔法世界

    Python数据类型探索列表魔法世界

    这篇文章主要为大家介绍了Python数据类型探索列表魔法世界,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • Python实现输出某区间范围内全部素数的方法

    Python实现输出某区间范围内全部素数的方法

    这篇文章主要介绍了Python实现输出某区间范围内全部素数的方法,涉及Python数值运算、排序、判断等相关操作技巧,需要的朋友可以参考下
    2018-05-05

最新评论