01. 贪婪与非贪婪匹配
正则表达式的贪婪和非贪婪匹配决定了量词的行为方式。
贪婪匹配(默认):
- 尽可能多地匹配字符
- 从左到右尝试,直到失败
非贪婪匹配(懒惰匹配):
- 在量词后加 ? 使匹配尽可能少
- 如 *?、+?、??、{n,m}?
python
import re
text = '<div>内容1</div><div>内容2</div>'
# 贪婪匹配(默认)
greedy = re.findall(r'<div>.*</div>', text)
print("贪婪:", greedy)
# ['<div>内容1</div><div>内容2</div>']
# 非贪婪匹配
lazy = re.findall(r'<div>.*?</div>', text)
print("非贪婪:", lazy)
# ['<div>内容1</div>', '<div>内容2</div>']
# 实际应用:提取 HTML 内容
html = '<p>第一段</p><p>第二段</p><p>第三段</p>'
paragraphs = re.findall(r'<p>(.*?)</p>', html)
print("段落:", paragraphs)
# ['第一段', '第二段', '第三段']
# 提取引号中的内容
text2 = '他说"你好",然后说"再见"'
quotes = re.findall(r'"(.*?)"', text2)
print("引号内容:", quotes)
# ['你好', '再见']02. 分组与捕获
分组是正则表达式的核心特性,用于捕获匹配的子串。
分组类型:
- 普通分组:(pattern)
- 命名分组:(?P<name>pattern)
- 非捕获分组:(?:pattern)
- 前向断言:(?=pattern)、(?<=pattern)
- 后向断言:(?!pattern)、(?<!pattern)
python
import re
# 普通分组
text = "2026-01-15"
match = re.search(r'(\d{4})-(\d{2})-(\d{2})', text)
if match:
print("完整匹配:", match.group(0)) # 2026-01-15
print("年份:", match.group(1)) # 2026
print("月份:", match.group(2)) # 01
print("日期:", match.group(3)) # 15
# 命名分组
match = re.search(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})', text)
if match:
print("年份:", match.group('year'))
print("月份:", match.group('month'))
# 非捕获分组
text = "http://example.com https://secure.com"
urls = re.findall(r'(?:http|https)://([^/]+)', text)
print("域名:", urls)
# 前向断言(肯定)
text = "价格: 100元 数量: 200"
numbers = re.findall(r'\d+(?=元)', text) # 后面是"元"的数字
print("价格:", numbers) # ['100']
# 后向断言(肯定)
numbers2 = re.findall(r'(?<=数量: )\d+', text) # 前面是"数量: "的数字
print("数量:", numbers2) # ['200']
# 分组替换
text = "张三 13812345678 李四 13987654321"
masked = re.sub(r'(\d{3})\d{4}(\d{4})', r'\1\2', text)
print("脱敏:", masked)03. 断言与零宽断言
断言(零宽断言)匹配一个位置而不是字符,用于精确匹配。
四种零宽断言:
- (?=pattern):肯定先行断言(后面是 pattern)
- (?!pattern):否定先行断言(后面不是 pattern)
- (?<=pattern):肯定后行断言(前面是 pattern)
- (?<!pattern):否定后行断言(前面不是 pattern)
python
import re
# 肯定先行断言 (?=...)
# 匹配后面跟着 "元" 的数字
text = "价格: 100元 数量: 200个"
result = re.findall(r'\d+(?=元)', text)
print("价格:", result) # ['100']
# 否定先行断言 (?!...)
# 匹配后面不跟着 "个" 的数字
result2 = re.findall(r'\d+(?!个)', text)
print("不含个的数字:", result2)
# 肯定后行断言 (?<=...)
# 匹配前面是 "价格: " 的数字
result3 = re.findall(r'(?<=价格: )\d+', text)
print("价格:", result3) # ['100']
# 否定后行断言 (?<!...)
# 匹配前面不是 "价格: " 的数字
result4 = re.findall(r'(?<!价格: )\d+', text)
print("其他数字:", result4)
# 实际应用:提取 HTML 标签内容(不使用分组)
html = '<b>粗体</b> 和 <i>斜体</i>'
tags = re.findall(r'(?<=<b>).*?(?=</b>)', html)
print("粗体内容:", tags)
# 密码强度验证
def check_password(password):
patterns = {
'长度': r'(?=^.{8,})',
'大写字母': r'(?=.*[A-Z])',
'小写字母': r'(?=.*[a-z])',
'数字': r'(?=.*\d)',
'特殊字符': r'(?=.*[@$!%*?&])'
}
for name, pattern in patterns.items():
if not re.search(pattern, password):
return f"缺少: {name}"
return "密码强度合格"
print(check_password("Abc123@#"))知识测验
第 1/4 题正确 0
贪婪匹配和非贪婪匹配的区别是什么?
下一节
下一节 操作系统基础