各位小伙伴好,我是唐叔!今天咱们来聊聊Python中的正则表达式——这个让无数程序员又爱又恨的"黑魔法"。正则表达式就像是一把瑞士军刀,能轻松解决字符串匹配、提取、替换等复杂问题。别被它的语法吓到,跟着唐叔学,5分钟就能上手!
一、正则表达式是啥?为啥要用它?
一句话解释:正则表达式(Regular Expression,简称regex)就是用来匹配字符串的规则。比如:
- 检查手机号格式是否正确
- 从网页源码中提取所有链接
- 批量替换文本中的敏感词
不用正则的痛:
# 判断手机号是否合法(11位数字)
phone = "13800138000"
if len(phone) == 11 and phone.isdigit():
print("合法")
else:
print("不合法")
用正则的爽:
import re
phone = "13800138000"
if re.match(r"^\d{11}$", phone):
print("合法")
else:
print("不合法")
二、5大核心操作,快速上手正则
1. 匹配:re.match()
vs re.search()
match()
:从字符串开头匹配search()
:在字符串中搜索匹配
import re
# match示例
text = "Python is awesome"
print(re.match(r"Python", text)) # 匹配成功
print(re.match(r"awesome", text)) # 匹配失败(因为不是开头)
# search示例
print(re.search(r"awesome", text)) # 匹配成功
记忆口诀:match
看开头,search
随便搜!
2. 查找所有:re.findall()
提取字符串中所有符合规则的子串:
text = "我的电话是13800138000,你的电话是13912345678"
phones = re.findall(r"\d{11}", text)
print(phones) # 输出: ['13800138000', '13912345678']
记忆口诀:findall
全抓取,返回列表不用愁!
3. 替换:re.sub()
批量替换字符串中的内容:
text = "Python是最好的语言!Java也是最好的语言!"
new_text = re.sub(r"最好的语言", "yyds", text)
print(new_text) # 输出: Python是yyds!Java也是yyds!
记忆口诀:sub
替换忙,一键全改光!
4. 分割:re.split()
按规则切割字符串:
text = "Python,Java;C++|JavaScript"
langs = re.split(r"[,;|]", text)
print(langs) # 输出: ['Python', 'Java', 'C++', 'JavaScript']
记忆口诀:split
切割忙,规则随便放!
5. 分组提取:()
用括号分组,提取特定部分:
text = "姓名: 唐叔, 年龄: 18"
match = re.search(r"姓名: (\w+), 年龄: (\d+)", text)
if match:
print(f"姓名: {match.group(1)}, 年龄: {match.group(2)}")
# 输出: 姓名: 唐叔, 年龄: 18
记忆口诀:括号来分组,group
轻松取!
三、正则表达式语法速记表
符号 | 含义 | 示例 |
---|---|---|
\d | 匹配数字 | \d{3} 匹配3位数字 |
\w | 匹配字母数字 | \w+ 匹配一个单词 |
. | 匹配任意字符 | a.b 匹配a和b之间的任意字符 |
* | 匹配0次或多次 | a* 匹配0个或多个a |
+ | 匹配1次或多次 | a+ 匹配1个或多个a |
? | 匹配0次或1次 | a? 匹配0个或1个a |
{n} | 匹配n次 | \d{4} 匹配4位数字 |
[] | 匹配括号内任意字符 | [abc] 匹配a、b或c |
记忆口诀:
\d
是数字,\w
是字母.
是任意,*
是0到多+
是1到多,?
是0或1{n}
是固定次数,[]
是选一个
四、如何高效自定义正则表达式
正则表达式的强大之处在于它的灵活性,但如何高效地自定义正则表达式呢?唐叔教你几招!
1. 明确需求,分步构建
不要试图一次性写出完美的正则表达式,先分解需求,逐步构建。
示例:匹配一个合法的日期格式(YYYY-MM-DD)
- 第一步:匹配4位年份
\d{4}
- 第二步:匹配分隔符
-
- 第三步:匹配2位月份
\d{2}
- 第四步:匹配2位日期
\d{2}
- 最终组合:
\d{4}-\d{2}-\d{2}
2. 使用在线工具调试
推荐使用在线正则表达式调试工具,如 regex101 、 regexr或debuggex,实时查看匹配结果。
当然如果使用VS Code进行开发,也可以考虑使用VS Code插件:Regex Previewer或RegExp Explain。
3. 避免贪婪匹配
默认情况下,正则表达式是贪婪的(尽可能多匹配),可以通过?
改为非贪婪模式。
示例:
text = "<div>Python</div><div>Java</div>"
print(re.findall(r"<div>(.*)</div>", text)) # 贪婪:['Python</div><div>Java']
print(re.findall(r"<div>(.*?)</div>", text)) # 非贪婪:['Python', 'Java']
4. 合理使用分组
分组不仅可以提取数据,还能让正则表达式更清晰。
示例:提取URL中的协议和域名
url = "https://www.csdn.net"
match = re.match(r"(https?)://([^/]+)", url)
if match:
print(f"协议: {match.group(1)}, 域名: {match.group(2)}")
# 输出: 协议: https, 域名: www.csdn.net
5. 预编译正则表达式
如果需要多次使用同一个正则表达式,可以使用re.compile()
预编译,提升效率。
示例:
pattern = re.compile(r"\d{11}")
print(pattern.match("13800138000")) # 匹配成功
五、避坑指南
- 贪婪匹配:默认是贪婪模式(尽可能多匹配),加
?
变非贪婪
text = "<div>Python</div><div>Java</div>"
print(re.findall(r"<div>(.*)</div>", text)) # 贪婪:['Python</div><div>Java']
print(re.findall(r"<div>(.*?)</div>", text)) # 非贪婪:['Python', 'Java']
- 原始字符串:正则表达式前加
r
,避免转义字符问题
# 错误写法
re.match("\d", "123") # 报错
# 正确写法
re.match(r"\d", "123") # 匹配成功
六、实战案例:提取邮箱地址
需求:从一段文本中提取所有合法的邮箱地址。
import re
text = """
联系我们:
客服邮箱:support@csdn.net
投诉邮箱:feedback@csdn.com
无效邮箱:admin@localhost
"""
# 定义邮箱正则规则
email_pattern = r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b"
# 提取邮箱
emails = re.findall(email_pattern, text)
print("提取到的邮箱地址:", emails)
输出结果:
提取到的邮箱地址: ['support@csdn.net', 'feedback@csdn.com']
唐叔总结
正则表达式就像是一把万能钥匙,能打开字符串处理的各种难题。今天咱们从匹配、查找、替换、分割到分组提取,一步步拆解了正则的核心操作。
当然也需要注意,正则表达式就像一把双刃剑:
- 用得好:代码简洁高效,老板直呼内行
- 用不好:同事看到你的正则,连夜提交离职申请
需要牢记:
- 复杂正则要写注释
- 超过3行的正则,就该考虑换方法了
- 能用字符串方法解决的,别用正则(比如str.replace())
附录:常见正则表达式示例
以下是常见的正则表达式使用场景及其对应的正则规则,帮助大家快速上手:
场景描述 | 正则表达式示例 | 代码示例 |
---|---|---|
匹配手机号 | ^\d{11}$ | re.match(r"^\d{11}$", "13800138000") |
匹配邮箱地址 | \b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b | re.findall(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b", text) |
匹配URL | https?://[^\s]+ | re.findall(r"https?://[^\s]+", "Visit https://csdn.net for more info") |
匹配IP地址 | \b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b | re.match(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b", "192.168.1.1") |
匹配日期(YYYY-MM-DD) | \d{4}-\d{2}-\d{2} | re.findall(r"\d{4}-\d{2}-\d{2}", "会议时间:2023-10-01") |
匹配中文 | [\u4e00-\u9fa5] | re.findall(r"[\u4e00-\u9fa5]", "Python真香!") |
匹配HTML标签 | <[^>]+> | re.findall(r"<[^>]+>", "<div>Python</div>") |
匹配空白行 | ^\s*$ | re.findall(r"^\s*$", " \n ") |
匹配密码强度(至少8位,包含大小写字母和数字) | ^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$ | re.match(r"^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$", "Passw0rd") |