Python正则表达式6大进阶实战题


以下是 6道Python正则表达式进阶题,覆盖「分组捕获、零宽断言、贪婪/非贪婪、反向引用、Unicode匹配、替换回调」等核心进阶知识点,结合实际应用场景设计,附详细提示和解答:

题目1:复杂邮箱地址提取(分组+非捕获组+贪婪控制)

题目要求:

从混合文本中提取所有邮箱地址,需支持两种格式:

纯邮箱:user.name+tag@domain.co.uk(用户名含 .+_,域名支持多级子域)带显示名的邮箱:“张三” zhangsan-123@mail.qq.com 或 李四 lisi@company.io(显示名可能带引号/空格,邮箱用尖括号包裹)

提取目标:

每个邮箱需返回「显示名(无则为None)、用户名、完整域名」

输入示例:


text = '''
联系邮箱:"张三" <zhangsan-123@mail.qq.com>,备用邮箱 lisi+work@company.io,
还有 admin._root@sub.domain.com,以及错误格式 <invalid-email@.com>(需过滤)。
'''

输出示例:


[
    ("张三", "zhangsan-123", "mail.qq.com"),
    (None, "lisi+work", "company.io"),
    (None, "admin._root", "sub.domain.com")
]

涉及知识点:

非捕获组 (?😃、捕获组、贪婪/非贪婪匹配、字符类扩展、域名多级匹配

提示:

显示名部分:可选,可能带双引号,用 (?:[“']?(.?)[“']?s<)? 匹配用户名部分:允许 a-zA-Z0-9.±,用 [a-zA-Z0-9.±]+域名部分:支持多级子域(如 sub.domain.com),用 [a-zA-Z0-9-]+.[a-zA-Z0-9-.]+(注意避免匹配 .com. 这类非法结尾)

题目2:HTML标签内容提取与清理(零宽断言+多行模式)

题目要求:

从HTML片段中提取所有


标签内的文本(忽略标签内的子标签,如 )清理文本中的多余空格(连续空格合并为一个,首尾空格去除)

输入示例:


html = '''
<div class="header">标题</div>
<div class="content">
  这是第一段内容,<span>包含子标签</span>,还有  多余  空格。
</div>
<div class="content">第二段内容,无子类<span>标签</span>,结尾有空格 </div>
<div class="footer">底部</div>
'''

输出示例:

[“这是第一段内容,包含子标签,还有 多余 空格。”, “第二段内容,无子类标签,结尾有空格”]

涉及知识点:

零宽断言(正向先行 (?<=)、反向先行 (?!))、多行模式 re.DOTALL、替换函数 re.sub

提示:

用正向先行断言匹配

开头,反向先行断言匹配
结尾,避免捕获标签本身用 re.DOTALL 让 . 匹配换行符(标签内可能换行)用 re.sub(r’s+', ’ ', text).strip() 清理空格

题目3:密码强度校验(正向先行断言+字符类)

题目要求:

设计正则表达式,校验密码是否满足以下所有条件:

长度 8-20 个字符必须包含至少 1 个大写字母(A-Z)必须包含至少 1 个小写字母(a-z)必须包含至少 1 个数字(0-9)必须包含至少 1 个特殊符号(!@#$%^&*()_±=[]{}|;:,.?~)不能包含空格、制表符等空白字符

输入示例:


passwords = ["Pass123!", "weakpassword", "Strong@2025", "Short1!", "NoSpecial123", "Has Space1!"]

输出示例:


[True, False, True, False, False, False]

涉及知识点:

正向先行断言 (?=)、字符类、长度限制 {m,n}、否定字符类 [^…]

提示:

用多个正向先行断言分别校验“必须包含的字符类型”用 [^s] 排除空白字符整体结构:^(?=.[A-Z])(?=.[a-z])(?=.d)(?=.[!@#

%^&*()_+-=[]{}|;:,.?~])[^\s]{8,20}

题目4:日志条目结构化解析(分组+多行匹配)

题目要求:

从服务器日志中提取每条日志的「时间戳、日志级别、模块名、错误信息」,日志格式如下:

时间戳:YYYY-MM-DD HH:MM:SS(如 2025-11-13 14:30:25)日志级别:INFO/WARN/ERROR/FATAL(大写,用方括号包裹)模块名:[模块名](如 [UserService]、[OrderDB])错误信息:冒号后到行尾的所有内容(可能包含空格、特殊符号)

输入示例:


log = '''
2025-11-13 14:30:25 [INFO] [UserService] 用户登录成功,ID:1001
2025-11-13 14:32:10 [WARN] [OrderDB] 数据库连接超时,重试第1次
2025-11-13 14:33:05 [ERROR] [PaymentAPI] 支付失败:金额格式错误(value=abc123)
2025-11-13 14:35:40 [FATAL] [SystemCore] 核心服务崩溃:内存溢出
'''

输出示例:


[
    ("2025-11-13 14:30:25", "INFO", "UserService", "用户登录成功,ID:1001"),
    ("2025-11-13 14:32:10", "WARN", "OrderDB", "数据库连接超时,重试第1次"),
    ("2025-11-13 14:33:05", "ERROR", "PaymentAPI", "支付失败:金额格式错误(value=abc123)"),
    ("2025-11-13 14:35:40", "FATAL", "SystemCore", "核心服务崩溃:内存溢出")
]

涉及知识点:

捕获组、字符类、多行模式 re.MULTILINE、非贪婪匹配

提示:

时间戳匹配:d{4}-d{2}-d{2} d{2}:d{2}:d{2}日志级别匹配:[(INFO|WARN|ERROR|FATAL)](用分组提取)模块名匹配:[(.*?)](非贪婪匹配方括号内内容)错误信息匹配::s*(.*)(冒号后所有内容,含空格和特殊符号)

题目5:重复内容去重与日期标准化(反向引用+替换回调)

题目要求:

去除文本中连续重复的单词(如 hello hello world → hello world,test test test → test)将文本中所有日期格式统一为 YYYY-MM-DD(支持原格式:YYYY/MM/DD、YYYY.MM.DD、YYYY-MM-DD)

输入示例:


text = '''
2025/11/13 今天天气很好,很好!我们我们讨论了 2025.10.01 的计划,
以及 2024-09-20 的会议记录,重复重复的单词需要需要去重。
'''

输出示例:


"2025-11-13 今天天气很好!我们讨论了 2025-10-01 的计划,以及 2024-09-20 的会议记录,重复的单词需要去重。"

涉及知识点:

反向引用 1、替换回调函数 re.sub(repl=func)、字符类 [./-]

提示:

连续重复单词匹配:(w+)s+1( 是单词边界,避免部分匹配,1 引用第一个分组的单词)日期标准化:用 re.sub(r’(d{4})./-./-‘, r’1-2-3’, text) 替换分隔符

题目6:Unicode多语言文本匹配(中文/Emoji识别)

题目要求:

从混合文本中提取所有「中文姓名」(2-4个中文字符,不含数字和特殊符号)提取所有Emoji表情(仅匹配常见表情,如 😊🎉🔥,排除中文符号)统计中文姓名和Emoji的数量

输入示例:


text = '''
参会人员:张三、李四华、王五123(非法)、赵六六六(4字)、陈五(2字)
会议情绪:😊 开心、🎉 顺利、🔥 紧急,还有中文符号:。,!(不算Emoji)
'''

输出示例:


{
    "中文姓名": ["张三", "李四华", "赵六六六", "陈五"],
    "Emoji": ["😊", "🎉", "🔥"],
    "姓名数量": 4,
    "Emoji数量": 3
}

涉及知识点:

Unicode属性匹配(p{})、字符类范围、re.UNICODE 模式

提示:

中文姓名匹配:[u4e00-u9fa5]{2,4}(u4e00-u9fa5 是中文Unicode范围)Emoji匹配:利用Unicode属性 p{Emoji}(需Python 3.7+,且正则模式加 re.UNICODE 或 re.U)排除非法姓名:用 (?![u4e00-u9fa5]*d) 正向先行断言排除含数字的姓名


解答(逐题解析)

题目1:复杂邮箱地址提取


import re

text = '''
联系邮箱:"张三" <zhangsan-123@mail.qq.com>,备用邮箱 lisi+work@company.io,
还有 admin._root@sub.domain.com,以及错误格式 <invalid-email@.com>(需过滤)。
'''

正则表达式:非捕获组控制显示名可选,捕获组提取关键信息

pattern = r’(?:[“‘]?(.?)[“']?s<)?([a-zA-Z0-9._±]+)@([a-zA-Z0-9-]+.[a-zA-Z0-9-.]+)(?:>)?’

解析:

(?:[“']?(.?)[“']?s<)? → 可选显示名(带引号/空格,非捕获组)

([a-zA-Z0-9._±]+) → 捕获用户名(允许合法特殊符号)

@ → 邮箱分隔符

([a-zA-Z0-9-]+.[a-zA-Z0-9-.]+) → 捕获多级域名

(?:>) → 可选的尖括号结尾(非捕获组)

matches = re.findall(pattern, text, re.DOTALL)

过滤非法域名(如 @.com)

result = []
for name, user, domain in matches:
if not domain.startswith(‘.’) and not domain.endswith(‘.’):
result.append( (name.strip() if name else None, user, domain) )

print(result)

输出:[(“张三”, “zhangsan-123”, “mail.qq.com”), (None, “lisi+work”, “company.io”), (None, “admin._root”, “sub.domain.com”)]

题目2:HTML标签内容提取与清理


import re

html = '''
<div class="header">标题</div>
<div class="content">
  这是第一段内容,<span>包含子标签</span>,还有  多余  空格。
</div>
<div class="content">第二段内容,无子类<span>标签</span>,结尾有空格 </div>
<div class="footer">底部</div>
'''

正则:正向先行匹配开头标签,反向先行匹配结尾标签,DOTALL允许.匹配换行

pattern = r’(?<=

).*?(?=
)’

contents = re.findall(pattern, html, re.DOTALL)

清理空格和子标签


cleaned = []
for content in contents:
    # 去除子标签(<.*?> 匹配任意标签)
    no_tags = re.sub(r'<.*?>', '', content)
    # 合并连续空格,去除首尾空格
    cleaned_text = re.sub(r's+', ' ', no_tags).strip()
    cleaned.append(cleaned_text)

print(cleaned)

输出:[“这是第一段内容,包含子标签,还有 多余 空格。”, “第二段内容,无子类标签,结尾有空格”]

题目3:密码强度校验


import re

def is_strong_password(password):
    # 正则:多个正向先行断言校验条件,[^\s]排除空白字符
    pattern = r'^(?=.*[A-Z])(?=.*[a-z])(?=.*d)(?=.*[!@#$%^&*()_+-=[]{}|;:,.?~])[^\s]{8,20}$'
    return bool(re.match(pattern, password))

passwords = ["Pass123!", "weakpassword", "Strong@2025", "Short1!", "NoSpecial123", "Has Space1!"]
results = [is_strong_password(pwd) for pwd in passwords]
print(results)

输出:[True, False, True, False, False, False]

题目4:日志条目结构化解析


import re

log = '''
2025-11-13 14:30:25 [INFO] [UserService] 用户登录成功,ID:1001
2025-11-13 14:32:10 [WARN] [OrderDB] 数据库连接超时,重试第1次
2025-11-13 14:33:05 [ERROR] [PaymentAPI] 支付失败:金额格式错误(value=abc123)
2025-11-13 14:35:40 [FATAL] [SystemCore] 核心服务崩溃:内存溢出
'''

正则:捕获时间戳、级别、模块名、错误信息

pattern = r’(d{4}-d{2}-d{2} d{2}:d{2}:d{2}) [(INFO|WARN|ERROR|FATAL)] [(.?)] (.)’
matches = re.findall(pattern, log, re.MULTILINE)
print(matches)

输出与题目要求一致

题目5:重复内容去重与日期标准化


import re

text = '''
2025/11/13 今天天气很好,很好!我们我们讨论了 2025.10.01 的计划,
以及 2024-09-20 的会议记录,重复重复的单词需要需要去重。
'''

1. 日期标准化:替换 / . 为 –


text = re.sub(r'(d{4})[./-](d{2})[./-](d{2})', r'1-2-3', text)

2. 重复单词去重:用回调函数替换(处理多次重复,如 AAA → A)


def remove_duplicates(match):
    return match.group(1)

单词边界,避免部分匹配(如 “aaaa” 不匹配 “aa aa”)


text = re.sub(r'(w+)s+1', remove_duplicates, text)

处理多次重复(如 “aaa aaa aaa” → “aaa”)


while re.search(r'(w+)s+1', text):
    text = re.sub(r'(w+)s+1', remove_duplicates, text)

print(text.strip())

输出:“2025-11-13 今天天气很好!我们讨论了 2025-10-01 的计划,以及 2024-09-20 的会议记录,重复的单词需要去重。”

题目6:Unicode多语言文本匹配


import re

text = '''
参会人员:张三、李四华、王五123(非法)、赵六六六(4字)、陈五(2字)
会议情绪:😊 开心、🎉 顺利、🔥 紧急,还有中文符号:。,!(不算Emoji)
'''

1. 提取中文姓名(2-4字中文,不含数字)


name_pattern = r'(?![u4e00-u9fa5]*d)[u4e00-u9fa5]{2,4}'
names = re.findall(name_pattern, text)

2. 提取Emoji(Python 3.7+ 支持 p{Emoji})


emoji_pattern = r'p{Emoji}'
emojis = re.findall(emoji_pattern, text, re.UNICODE)

3. 统计结果


result = {
    "中文姓名": names,
    "Emoji": emojis,
    "姓名数量": len(names),
    "Emoji数量": len(emojis)
}

print(result)

输出:{“中文姓名”: [“张三”, “李四华”, “赵六六六”, “陈五”], “Emoji”: [“😊”, “🎉”, “🔥”], “姓名数量”: 4, “Emoji数量”: 3}

学习建议

每道题先自己尝试写正则,再对照解答,重点关注「为什么这么写」(如非捕获组的作用、断言的逻辑)用 re.findall() 验证匹配结果,用 re.match()/re.search() 调试单个匹配遇到复杂正则时,拆分片段逐步测试(如先匹配时间戳,再匹配日志级别,最后合并)结合实际场景记忆知识点(如密码校验用先行断言,日志解析用分组捕获)

通过这些题目,能熟练掌握Python正则的进阶用法,应对工作中的复杂文本处理场景!

© 版权声明

相关文章

暂无评论

none
暂无评论...