当前位置:首页 > 技术 > 正文内容

Python正则表达式核心语法与re模块实战解析

访客 技术 2026年5月23日 3

正则表达式应用场景

在软件开发中,我们经常需要处理复杂的文本数据。以下是几个典型的文本匹配场景:

  • 从服务器日志中筛选出所有以 ERROR 开头的异常记录。
  • 在用户输入中验证是否包含合法的 github.comgitlab.com 链接。
  • 从海量数据中提取所有使用特定后缀(如 @outlook.com@hotmail.com)的电子邮箱。

正则表达式(Regular Expression)正是解决这类字符串匹配、提取和替换问题的强大工具。

re模块基础操作

Python 提供了内置的 re 模块来支持正则表达式操作。最常用的入门方法是 re.match(),它用于从字符串的起始位置进行匹配。

基本使用流程

import re

# 编译或直接使用正则表达式进行匹配
pattern = r"devhub"
text = "devhub.io"
match_obj = re.match(pattern, text)

# 检查是否匹配成功并提取结果
if match_obj:
    print(match_obj.group())

匹配起始字符串

import re

# 匹配以 techblog 开头的字符串
result = re.match(r"techblog", "techblog.net")
print(result.group())  # 输出: techblog

注意re.match() 仅从字符串的开头开始匹配,如果起始位置不符合规则,即使字符串中间包含目标内容也会返回 None

单字符匹配规则

正则表达式提供了一系列元字符来匹配单个特定类型的字符:

元字符匹配规则
.匹配除换行符 \n 之外的任意单个字符
[ ]匹配方括号内列举的任意一个字符
\d匹配任意数字(等同于 [0-9]
\D匹配任意非数字字符
\s匹配任意空白字符(空格、制表符等)
\S匹配任意非空白字符
\w匹配字母、数字及下划线(等同于 [a-zA-Z0-9_]
\W匹配非单词字符

点号(.)与方括号([ ])示例

import re

# 匹配任意单个字符
print(re.match(r".", "Z").group())  # 输出: Z

# 匹配 c_t 格式(中间任意字符)
print(re.match(r"c.t", "cat").group())  # 输出: cat
print(re.match(r"c.t", "cut").group())  # 输出: cut

# 使用方括号匹配大小写
print(re.match(r"[pP]ython", "python").group())  # 输出: python
print(re.match(r"[pP]ython", "Python").group())  # 输出: Python

# 匹配特定范围的数字
print(re.match(r"[1-5]version", "3version").group())  # 输出: 3version

数字匹配(\d)示例

import re

# 传统精确匹配
print(re.match(r"TianGong-1", "TianGong-1 launched").group())

# 使用 \d 匹配任意数字
print(re.match(r"TianGong-\d", "TianGong-2 launched").group())
print(re.match(r"TianGong-\d", "TianGong-3 launched").group())

多字符匹配(量词)

当需要匹配不定长或特定长度的字符串时,需要用到量词:

量词匹配规则
*匹配前一个字符 0 次或无数次
+匹配前一个字符 1 次或无数次
?匹配前一个字符 0 次或 1 次
{m}精确匹配前一个字符 m 次
{m,n}匹配前一个字符 m 到 n 次

量词实战演练

import re

# * 示例:匹配大写字母后跟任意数量的小写字母
print(re.match(r"[A-Z][a-z]*", "Hello").group())  # 输出: Hello
print(re.match(r"[A-Z][a-z]*", "A").group())      # 输出: A

# + 示例:验证合法的标识符(字母或下划线开头,后跟任意单词字符)
identifiers = ["valid_var", "_private", "9invalid", "CamelCase"]
for var in identifiers:
    if re.match(r"[a-zA-Z_]\w*", var):
        print(f"{var} 是合法标识符")
    else:
        print(f"{var} 非法")

# ? 示例:匹配 0-99 的数字
print(re.match(r"[1-9]?\d$", "7").group())   # 输出: 7
print(re.match(r"[1-9]?\d$", "42").group())  # 输出: 42

# {m,n} 示例:验证 8 到 16 位的字母数字密码
pwd_pattern = r"[A-Za-z0-9]{8,16}$"
print(re.match(pwd_pattern, "Pass1234").group())  # 输出: Pass1234

边界匹配

为了确保整个字符串完全符合规则,而不是仅仅匹配前缀,我们需要使用边界符:

符号功能
^匹配字符串的开头(在 re.match 中默认包含)
$匹配字符串的结尾

结尾匹配($)示例

import re

emails = ["alice@gmail.com", "bob@gmail.com.cn", "test@yahoo.com"]
pattern = r"[\w]{4,20}@gmail\.com$"

for email in emails:
    match_res = re.match(pattern, email)
    if match_res:
        print(f"{email} 验证通过")
    else:
        print(f"{email} 格式不符")

通过添加 $bob@gmail.com.cn 将被正确识别为不合规的邮箱地址。

分组与引用

分组允许我们将多个字符组合成一个单元,并支持逻辑或、数据提取以及反向引用。

语法功能说明
|逻辑或,匹配左右任意一个表达式
(ab)将括号内的规则作为一个分组
\num反向引用第 num 个分组匹配到的文本
(?P<name>)为分组指定别名
(?P=name)引用别名为 name 的分组内容

逻辑或与分组提取

import re

# 匹配 0-100 的数值
num_pattern = r"^([1-9]?\d|100)$"
print(re.match(num_pattern, "88").group())  # 输出: 88

# 提取特定域名的邮箱
domain_pattern = r"\w{4,20}@(gmail|yahoo|outlook)\.com$"
match_obj = re.match(domain_pattern, "user123@yahoo.com")
print(match_obj.group())   # 完整匹配: user123@yahoo.com
print(match_obj.group(1))  # 分组1: yahoo

# 提取区号与电话号码
phone_match = re.match(r"(\d{3,4})-(\d{7,8})", "010-88889999")
print(f"区号: {phone_match.group(1)}, 号码: {phone_match.group(2)}")

反向引用与别名

import re

# 匹配成对的 HTML 标签
html_str = "<div>Content</div>"
# 使用 \1 引用第一个分组
tag_pattern = r"<([a-z]+)>.*?"
print(re.match(tag_pattern, html_str).group())

# 匹配嵌套标签并使用别名
nested_html = "<article><p>Text</p></article>"
alias_pattern = r"<(?P<outer>[a-z]+)><(?P<inner>[a-z]+)>.*?"
nested_match = re.match(alias_pattern, nested_html)
print(nested_match.group())

re模块高级方法

除了 matchre 模块还提供了其他强大的文本处理函数。

search 与 findall

import re

# search: 扫描整个字符串,返回第一个成功的匹配
temp_str = "Current temperature is 24C"
temp_match = re.search(r"\d+", temp_str)
print(temp_match.group())  # 输出: 24

# findall: 查找所有匹配项,返回列表
log_data = "Errors: 404, 500, 502, 200"
error_codes = re.findall(r"\b[45]\d{2}\b", log_data)
print(error_codes)  # 输出: ['404', '500', '502']

sub 替换与 split 切割

import re

# sub: 替换匹配到的内容(支持函数作为替换逻辑)
def mask_phone(match_obj):
    phone = match_obj.group()
    return phone[:3] + "****" + phone[7:]

text = "Contact me at 13812345678"
print(re.sub(r"1\d{10}", mask_phone, text))  # 输出: Contact me at 138****5678

# split: 根据正则规则切割字符串
csv_line = "apple, banana; orange|grape"
fruits = re.split(r"[,;|]\s*", csv_line)
print(fruits)  # 输出: ['apple', 'banana', 'orange', 'grape']

贪婪与非贪婪模式

正则表达式中的量词默认是贪婪的,即尽可能多地匹配字符。在量词后添加 ? 可以将其转换为非贪婪(懒惰)模式,即尽可能少地匹配。

import re

text = "StartTag-Content-EndTag"

# 贪婪模式:.* 会匹配到最后一个 '-'
greedy_match = re.search(r".*-", text)
print(greedy_match.group())  # 输出: StartTag-Content-

# 非贪婪模式:.*? 遇到第一个 '-' 就停止
lazy_match = re.search(r".*?-", text)
print(lazy_match.group())  # 输出: StartTag-

在提取HTML属性或特定标记内的内容时,非贪婪模式尤为重要,能有效防止匹配越界。

原生字符串(r前缀)的作用

在Python中,反斜杠 \ 用于转义字符。如果要在正则中匹配一个真实的反斜杠,传统的写法需要写四个反斜杠 \\\\,这被称为"转义地狱"。

import re

path_str = "C:\\Users\\Admin\\Docs"

# 普通字符串:需要双重转义
match_normal = re.match("C:\\\\Users", path_str)
print(match_normal.group())

# 原生字符串:在字符串前加 r,反斜杠不再转义
match_raw = re.match(r"C:\\Users", path_str)
print(match_raw.group())

强烈建议在编写正则表达式时始终使用 r"" 原生字符串格式,这能让正则规则更直观,避免不必要的转义错误。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。