Python入门教程丨3.5 正则表达式

news/2025/2/24 18:07:16

今天我们来学习 Python 里超实用的字符串匹配和正则表达式。这是处理文本数据的神器,无论是爬虫、数据清洗还是文本分析,都离不开它,我们从基础语法讲起,再到实战场景,深入体会正则的妙用。

1. re 库

正则表达式(Regular Expression,简称regex或regexp)是一种用来匹配字符串的强大工具。它由一串字符和特殊符号组成,用于描述或匹配一系列符合某种模式的字符串。正则表达式广泛应用于文本搜索、文本替换等操作中。Python中的re模块提供了对正则表达式的全面支持。

1.1 正则表达式基础语法

1.1.1 正则表达式基本元素
符号描述示例
.匹配除换行符外的任意字符a.c 可匹配 “abc”, “a1c” 等
^匹配字符串的开始^hello 匹配以 “hello” 开始的字符串
$匹配字符串的结束world$ 匹配以 “world” 结束的字符串
*匹配前面子表达式 0 次或多次ab*c 匹配 “ac”, “abc”, “abbc” 等
+匹配前面子表达式 1 次或多次ab+c 匹配 “abc”, “abbc” 等,但不匹配 “ac”
?匹配前面子表达式 0 次或 1 次colou?r 匹配 “color” 或 “colour”

.用来匹配除换行符外的任意字符

python">import re

# 示例:匹配号码格式的字符串
text = "我的号码是 A123-456 和 B789+012"
pattern = r"A1..-4.."
match = re.search(pattern, text)
print(match.group())  # 输出:A123-456
# 这里的 "A1..-4.." 中的每 “.” 都匹配一个字符,就像“万能胶” 

^匹配字符串的开始

python">import re

# 示例:检查用户名是否以特定前缀开头
text = "user12345"
pattern = r"^user"  # 匹配以 "user" 开头的字符串
match = re.search(pattern, text)
print("用户名以 'user' 开头:", bool(match))

$匹配字符串的结束

python">import re

# 示例:检查一段话是否以问句结束
text = "这是为什么呢?"
pattern = r"呢?$"  # 匹配以 "呢?" 结尾的字符串
match = re.search(pattern, text)
print("句子以 '呢?' 结尾:", bool(match))

*匹配前面子表达式 0 次或多次

python">import re

# 示例:匹配某人吃了多少块披萨
text = "他吃了披萨pizza, pppppizza, 和 pizza!"
pattern = r"p*izza"  # 匹配 "pizza" 或 "pppppizza" 等
matches = re.findall(pattern, text)
print(matches)  # 输出:['pizza', 'pppppizza', 'pizza']

+匹配前面子表达式 1 次或多次

python">import re

# 示例:匹配某人的电子邮件地址是否包含至少一个 @
text = "我的邮箱是 test@domain.com 和 another@test.com"
pattern = r"\w+@\w+\.\w+"  # 匹配包含至少一个 "@" 的邮箱地址
matches = re.findall(pattern, text)
print(matches)  # 输出:['test@domain.com', 'another@test.com']

?匹配前面子表达式 0 次或 1 次


1.1.2. 特殊字符集
符号描述示例
\d匹配一个数字字符\d\d\d-\d\d\d-\d\d\d\d 匹配电话号码格式
\D匹配非数字字符\D{3} 匹配三个非数字字符
\w匹配字母、数字或下划线\w+ 匹配单词
\W匹配非字母、数字或下划线\W+ 匹配非单词字符
\s匹配任何空白字符\s+ 匹配空格、制表符等

\d用来匹配一个数字字符

python">import re
text = "我有6颗苹果!"
pattern = r"我有 \d+ 颗苹果"  # 匹配以数字表示的苹果数量
print(re.findall(pattern, text))  # 输出:['我有6颗苹果']

\D匹配非数字字符

python">import re
text = "这是一段没有数字的文字!"
pattern = r"\D+"  # 匹配所有非数字字符
print(re.findall(pattern, text))  # 输出:['这是一段没有数字的文字!\n']
# 这里非数字字符的范围很广,包括了字母和标点

\w匹配字母、数字或下划线

python">import re
text = "我的用户名是_user123"
pattern = r"\w+"  # 匹配用户名中的字母、数字和下划线
print(re.findall(pattern, text))  # 输出:['我的用户名是', '_user123']

\W匹配非字母、数字或下划线,即匹配特殊字符

python">import re
text = "这是一段$带有特殊字符的文本!@#"
pattern = r"\W+"  # 匹配所有非字母、数字或下划线的字符
print(re.findall(pattern, text))  # 输出:['$', '!', '@#']

\s匹配任何空白字符

python">import re
text = "这是 一段有 多余空格 的 文本。"
pattern = r"\s+"  # 匹配文本中的所有空白字符
print(re.findall(pattern, text))  # 输出:[' ', ' ', ' ', ' ']

1.2 re模块常用函数

函数用法示例
search()扫描整个字符串并返回第一个成功的匹配re.search(r'ain', 'The rain in Spain')
match()尝试从字符串的起始位置匹配一个模式re.match(r'The', 'The rain in Spain')
findall()返回所有与模式匹配的列表re.findall(r'ain', 'The rain in Spain')
sub()替换所有匹配项为指定字符串re.sub(r'Spain', 'France', 'The rain in Spain')
split()根据模式分割字符串re.split(r'\s+', 'The rain in Spain')

re.search() 用于在字符串中寻找第一个匹配的模式。如果找到匹配,返回一个匹配对象,否则返回 None

python">import re
text = "Hello, World!"
pattern = r"World"
result = re.search(pattern, text)
if result:
    print("匹配成功!")
    print("匹配位置:", result.start(), result.end())
else:
    print("匹配失败!")
# 匹配成功!匹配位置: 7 12

re.findall() 用于找到字符串中所有匹配的模式,返回一个列表。

python">import re
text = "I have 1 apple, 2 bananas, and 3 oranges"
pattern = r"\d+"
result = re.findall(pattern, text)
print(result)  # 输出:['1', '2', '3']

re.sub() 用于替换字符串中匹配的模式。它会将所有匹配的内容替换为指定的字符串。

python">import re
text = "I have 1 apple, 2 bananas, and 3 oranges"
pattern = r"\d+"
replacement = "many"
result = re.sub(pattern, replacement, text)
print(result)  # 输出:I have many apple, many bananas, and many oranges

re.match() 专门用来匹配字符串开头的部分,如果字符串的开头符合给定的模式,它会返回一个匹配对象;否则返回 None

python">import re

# 示例:检查字符串是否以数字开头
text = "123 是一个数字"
pattern = r"\d+"  # 匹配一个或多个数字
# 使用 re.match()
result = re.match(pattern, text)
if result:
    print("匹配成功!匹配的内容是:", result.group())
else:
    print("匹配失败!")
#运行结果:匹配成功!匹配的内容是: 123

re.split() 可以根据指定的正则表达式模式将字符串分割成多个部分,并返回一个列表。

python">import re

# 示例:按逗号或空格分割字符串
text = "apple, banana orange,grape"
pattern = r"[,\s]+"  # 匹配逗号或空格
# 使用 re.split()
result = re.split(pattern, text)
print("分割后的结果:", result)
# 分割后的结果: ['apple', 'banana', 'orange', 'grape']

1.3 复杂模式

正则表达式不仅能匹配单个字符,还能通过一些特殊符号和语法构建复杂的匹配模式。下面我们来介绍几个常用的复杂模式构建方法。

符号用法示例
{n}匹配前一字符恰好 n 次a{2} 匹配 “aa”
{n,}至少匹配 n 次a{2,} 匹配 “aa”, “aaa” 等
{n,m}最少匹配 n 次且最多 m 次a{2,3} 匹配 “aa”, “aaa”
[abc]字符集合,匹配括号内任一字符[abc] 匹配 “a”, “b”, 或 “c”

{n}:该模式表示前一个字符必须出现恰好 n 次。

python">import re

# 示例:匹配恰好 4 个连续的 'a'
text = "aaaa"
pattern = r"a{4}"
match = re.match(pattern, text)
print(match.group() if match else "No match")  # 输出:aaaa

{n,}:至少匹配 n 次,该模式表示前一个字符至少出现 n 次,可以无限次。

python">import re

# 示例:匹配至少 2 个连续的 'a'
text = "aaaaaaaaaaa"
pattern = r"a{2,}"
match = re.match(pattern, text)
print(match.group() if match else "No match")  # 输出:aaaaaaaaaaa

{n,m}:该模式表示前一个字符至少出现 n 次,但不超过 m 次。

python">import re

# 示例:匹配 1 到 3 个连续的 'a'
text = "aaabb"
pattern = r"a{1,3}"
match = re.match(pattern, text)
print(match.group() if match else "No match")  # 输出:aaa

[abc]:该模式表示匹配括号内的任一字符。

python">import re

# 示例:匹配 'a' 或 'b' 或 'c'
text = "apple"
pattern = r"[abc]"
match = re.search(pattern, text)
print(match.group() if match else "No match")  # 输出:a

🎯Tips:

对于非常复杂的模式,建议分步骤构建并测试每个部分,想一口吃撑胖子很容易出错,分而治之是很好的思想。


1.4 贪婪与非贪婪模式

正则表达式中的贪婪模式和非贪婪模式是两种不同的匹配方式。在贪婪模式下,匹配尽可能多的字符,而非贪婪模式则匹配尽可能少的字符。

例如,对于字符串 “aaaab”,模式 “a+”(贪婪)将匹配整个 “aaaa”,而 “a+?”(非贪婪)将每次匹配一个 “a”。

1.4.1 贪婪模式

默认情况下,正则表达式的量词(如 *, +, ?, {n,}, {n,m})都是贪婪的,会尽可能多地匹配字符。

python">import re

text = "abbbc"
pattern = r"ab+"  # 贪婪模式,匹配尽可能多的 b
match = re.search(pattern, text)
print(match.group())  # 输出:abbb
# 这里的正则表达式会匹配尽可能多的 'b',因为它是贪婪的。
1.4.2 非贪婪模式

在量词后加上问号?,即可启用非贪婪模式,匹配尽可能少的字符。

python">import re

text = "abbbc"
pattern = r"ab+?"  # 非贪婪模式,匹配尽可能少的 b
match = re.search(pattern, text)
print(match.group())  # 输出:ab
# 这里的正则表达式会匹配最少的 'b',即只匹配一个 'b'。

在实际使用中,我们通常:

  • 使用 * 等贪婪匹配来处理简单的字符串操作。
  • 当需要精确控制匹配范围时,使用非贪婪模式来避免过度匹配。

例如我们在匹配网页源码时,匹配标签中的内容:

python">text = "I have <div>Hello, <span>World!</span></div>"
pattern_greedy = r"<.*>"
pattern_non_greedy = r"<.*?>"

result_greedy = re.findall(pattern_greedy, text)
result_non_greedy = re.findall(pattern_non_greedy, text)

print("贪婪匹配结果:", result_greedy)  # 输出:['<div>Hello, <span>World!</span></div>']
print("非贪婪匹配结果:", result_non_greedy)  # 输出:['<div>', '<span>']

2. 实际应用

2.1 邮箱/手机号格式验证

在用户注册或数据输入时,验证邮箱和手机号的格式是非常重要的。我们可以用正则表达式来实现。

(1)邮箱验证📧

python">import re

def validate_email(email):
    pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
    if re.match(pattern, email):
        return True
    else:
        return False

email = "test@exa@mple.com"
if validate_email(email):
    print("邮箱格式正确!")
else:
    print("邮箱格式错误!")

(2)手机号验证📱

python">import re
def validate_phone(phone):
    pattern = r"^1[3-9]\d{9}$"
    if re.match(pattern, phone):
        return True
    else:
        return False

phone = "13812345678"
if validate_phone(phone):
    print("手机号格式正确!")
else:
    print("手机号格式错误!")

(3)手机号提取📱

python">import re
phone_pattern = r"(?<!\d)(1[3-9]\d{9})(?!\d)"
text = "紧急联系13812345678,备用19198765432"
phones = re.findall(phone_pattern, text)
print("提取到的手机号:", phones)  
#提取到的手机号: ['13812345678', '19198765432']

2.2 HTML 文件解析

在爬虫或数据提取中,经常需要从 HTML 中提取内容。正则表达式可以帮助我们快速提取标签中的内容。

python">import re

html = """
<div class='news'>
    <h1>今日热榜</h1>
    <p>Python 3.12发布啦!</p>
</div>
"""

# 提取所有标签内容
contents = re.findall(r"<.*?>(.*?)</.*?>", html)
print("HTML内容提取:", contents)  # ['今日热榜', 'Python 3.12发布啦!']

# 提取指定标签内容
h1_content = re.search(r"<h1>(.*?)</h1>", html).group(1)
print("头条标题:", h1_content)  # 今日热榜

2.3 日志分析

在处理日志文件时,我们可能需要提取错误信息。正则表达式可以帮助我们快速过滤出错误信息。

python">log = """
[ERROR] 2023-08-10 14:22:35 数据库连接失败
[INFO] 2023-08-10 14:23:10 用户登录成功
[WARNING] 2023-08-10 14:24:02 内存使用率80%
"""

# 提取错误信息
errors = re.findall(r"\[ERROR\].+", log)
print("系统错误记录:", errors)  # ['[ERROR] 2023-08-10 14:22:35 数据库连接失败']

2.4 综合案例:简历解析

我们有一个简历文本,现在要使用正则提取其中的主要信息,保存到 json 中。

完整代码:

python">import re

resume = """
姓名:张三
电话:138-1234-5678
邮箱:zhangsan@example.com
技能:Python, 正则表达式, 数据分析

项目经验:
1. <项目名称>智能客服系统</项目名称>
   <描述>使用正则表达式实现对话指令解析</描述>
2. <项目名称>日志分析平台</项目名称>
   <描述>开发基于正则的日志过滤模块</描述>
"""

# 信息提取
def parse_resume(text):
    info = {
        "name": re.search(r"姓名:(.*)", text).group(1),
        "phone": re.search(r"电话:(.*)", text).group(1),
        "email": re.search(r"邮箱:(.*)", text).group(1),
        "skills": re.findall(r"技能:(.+)", text)[0].split(", "),
        "projects": re.findall(r"<项目名称>(.*?)</项目名称>\s+<描述>(.*?)</描述>", text)
    }
    return info

print(parse_resume(resume))

运行结果:

{'name': '张三', 'phone': '138-1234-5678', 'email': 'zhangsan@example.com', 'skills': ['Python', '正则表达式', '数据分析'], 'projects': [('智能客服系统', '使用正则表达式实现对话指令解析'), ('日志分析平台', '开发基于正则的日志过滤模块')]}

3. 辅助开发工具

在学习和使用正则表达式时,可以使用在线测试工具,如 regex101.com。它支持多种编程语言的正则表达式测试,还能提供详细的匹配结果和解释,非常方便。

🔧 RegEx 调试神器地址: regex101.com

  • 实时高亮匹配 → 高亮匹配结果
  • 解释模式 → 自动翻译正则语法
  • 测试用例库 → 自带常见场景用例


4. 小结

正则表达式是文本处理的强大工具,掌握了它,你就能轻松应对各种文本匹配和提取任务。在学习正则表达式的过程中,需要注意以下几点:

理解元字符的含义 :元字符是正则表达式的核心,需要熟练掌握各个元字符的含义和用法,如 .^$*+? 等。

注意特殊字符的转义 :在正则表达式中,一些特殊字符如 .*+ 等具有特殊含义,如果需要匹配这些字符本身,需要进行转义,即在字符前加上反斜杠 \

掌握常用函数的用法re 模块提供了许多常用的函数,如 search()match()findall()sub()split() 等,需要熟练掌握这些函数的用法和区别。

理解贪婪与非贪婪模式 :贪婪模式会尽可能多地匹配字符,而非贪婪模式则尽可能少地匹配字符。在实际应用中,需要根据具体需求选择合适的模式。

注意调试和优化 :在编写复杂的正则表达式时,要注意调试和优化,避免出现错误和性能问题。可以使用在线测试工具如 regex101.com 进行调试和测试。

多多练习,熟练掌握正则表达式,人人都能成为文本处理的高手!


http://www.niftyadmin.cn/n/5864687.html

相关文章

《解锁AI密码,机器人精准感知环境不再是梦!》

在科技飞速发展的当下&#xff0c;人工智能与机器人技术的融合正深刻改变着世界。其中&#xff0c;人工智能助力机器人实现更精准的环境感知&#xff0c;已成为该领域的核心课题&#xff0c;吸引着全球科研人员与科技企业的目光。这不仅关乎机器人能否在复杂环境中高效执行任务…

网络安全 | 信息安全管理体系(ISMS)

一、关于ISMS ISMS&#xff08;Information Security Management System&#xff0c;信息安全管理体系&#xff09;是组织在日常运营中管理信息安全风险的一种系统化方法&#xff0c;它基于预防、检测和响应的安全策略&#xff0c;确保信息资产的机密性、完整性和可用性。本次…

解耦的艺术_应用架构中的解耦

文章目录 Pre解耦的技术演化应用架构中的解耦小结 Pre 解耦的艺术_通过DPI依赖倒置实现解耦 解耦的艺术_通过中间层映射实现解耦 解耦的技术演化 技术的演化史&#xff0c;也是一部解耦的历史。从最初的面向对象编程&#xff08;OOP&#xff09;到Spring框架的依赖注入&…

API接口设计模式:从分层架构到CQRS的实战应用

以下将从分层架构和 CQRS&#xff08;命令查询职责分离&#xff09;的基本概念入手&#xff0c;为你阐述从分层架构到 CQRS 的实战应用相关内容&#xff1a; 分层架构 概念&#xff1a;分层架构是将系统按照功能划分为不同的层次&#xff0c;每个层次负责特定的职责&#xff0c…

【HarmonyOS Next】拒绝权限二次申请授权处理

【HarmonyOS Next】拒绝权限二次申请授权处理 一、问题背景&#xff1a; 在鸿蒙系统中&#xff0c;对于用户权限的申请&#xff0c;会有三种用户选择方式&#xff1a; 1.单次使用允许 2.使用应用期间&#xff08;长时&#xff09;允许 3.不允许 当用户选择不允许后&#xff0…

Java还是网络安全 java 网络安全面试题

&#x1f345; 点击文末小卡片 &#xff0c;免费获取网络安全全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1.网络七层协议 第一层&#xff1a;物理层 机械、电子、定时接口通信信道上的原始比特流传输 第二层&#xff1a;数据链路层 物理寻址&#xff0c;同时将原始比特…

谷歌浏览器更新后导致的刷新数据无法显示

这几天突然出现的问题&#xff0c;就是我做了一个网站&#xff0c;一直用Google展示&#xff0c;前两天突然就是刷新会丢失数据&#xff0c;然后再刷新几次吧又有了&#xff0c;之前一直好好的&#xff0c;后端也做了一些配置添加了CrossOrigin注解&#xff0c;然而换了edge浏览…

文档检索服务平台

文档检索服务平台是基于Elasticsearch的全文检索&#xff0c;包含数据采集、数据清洗、数据转换、数据检索等模块。 项目地址&#xff1a;Github、国内Gitee 演示地址&#xff1a;http://silianpan.cn/gdss/ 以下是演示角色和账号&#xff08;密码同账号&#xff09;&#xf…