正则表达式(Regular Expression,简称re或RegExp)本质上是一种用于描述字符串匹配规则的微型语言。想象你是一名图书管理员,需要快速找到所有以"Python"开头、以"编程"结尾的书名——正则表达式就是你手中的智能检索工具。
在Python中,正则表达式通过内置的re模块实现。这个模块就像瑞士军刀,提供了多种匹配方式:
re.match():从字符串开头严格匹配,像严格的安检员re.search():扫描整个字符串寻找匹配,像寻宝探测器re.findall():找出所有匹配项,像高效的收割机re.sub():替换匹配内容,像文字编辑的查找替换功能实际开发中,90%的正则需求都能用现成的表达式解决。重点在于理解规则而非创造新轮子。
| 字符 | 含义 | 示例 | 匹配结果 |
|---|---|---|---|
. |
除换行外的任意字符 | a.c |
"abc", "a c", "a$c" |
\d |
数字字符 | \d\d |
"42", "01" |
\w |
单词字符(字母/数字/下划线) | \w+ |
"hello", "user123" |
\s |
空白字符 | a\sb |
"a b", "a\tb" |
| 量词 | 含义 | 示例 | 匹配结果 |
|---|---|---|---|
? |
0或1次 | colou?r |
"color", "colour" |
* |
0次或多次 | go*gle |
"ggle", "google" |
+ |
1次或多次 | go+gle |
"gogle", "gooogle" |
{n,m} |
n到m次 | \d{3,5} |
"123", "12345" |
^:字符串开头(或行的开头在多行模式)$:字符串结尾(或行的结尾在多行模式)\b:单词边界python复制# 验证手机号格式
pattern = r'^1[3-9]\d{9}$'
re.match(pattern, "13800138000") # 匹配
re.match(pattern, "12345678901") # 不匹配
分组就像给匹配内容贴标签:
python复制# 提取日期组件
date_pattern = r'(\d{4})-(\d{2})-(\d{2})'
match = re.match(date_pattern, "2023-08-15")
if match:
year, month, day = match.groups() # ('2023', '08', '15')
(?:...):非捕获分组(不存储匹配内容)(?P<name>...):命名分组(通过名称引用)python复制# 命名分组示例
text = "James: 32, Emma: 28"
pattern = r'(?P<name>\w+):\s*(?P<age>\d+)'
for match in re.finditer(pattern, text):
print(f"{match.group('name')} is {match.group('age')} years old")
| 技巧 | 语法 | 示例 | 说明 |
|---|---|---|---|
| 正向先行断言 | (?=...) |
\w+(?=\.) |
匹配后面跟着点的单词 |
| 负向先行断言 | (?!...) |
\d{3}(?!\d) |
匹配不以数字结尾的3位数 |
| 正向后行断言 | (?<=...) |
(?<=\$)\d+ |
匹配$后面的数字 |
| 负向后行断言 | (?<!...) |
(?<!-)\d+ |
匹配不以-开头的数字 |
对于频繁使用的正则表达式,预编译可提升性能:
python复制email_pattern = re.compile(
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
re.IGNORECASE
)
# 复用编译后的模式
if email_pattern.match("user@example.com"):
print("Valid email")
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 匹配不到预期结果 | 未考虑多行模式 | 添加re.MULTILINE标志 |
| 匹配结果包含多余部分 | 贪婪匹配 | 使用非贪婪量词*?或+? |
| 特殊字符未转义 | 未对.$^*+?{}[]|()转义 |
使用re.escape() |
| 性能低下 | 回溯过多 | 优化表达式结构,避免嵌套量词 |
python复制log_pattern = r'ERROR\s+(\d{3}):\s+(.*?)at\s+(.*?)\.py'
errors = re.findall(log_pattern, log_content)
python复制phone_pattern = re.compile(r'(\d{3})[-.\s]?(\d{4})[-.\s]?(\d{4})')
cleaned = phone_pattern.sub(r'\1-\2-\3', raw_phone)
python复制template = "Hello {name}, your code is {code}"
data = {"name": "Alice", "code": "X42B"}
result = re.sub(r'\{(\w+)\}', lambda m: data[m.group(1)], template)
python复制def validate_input(pattern, text):
return bool(re.fullmatch(pattern, text))
# 用户名:字母开头,4-16字符
username_re = r'^[a-zA-Z]\w{3,15}$'
# 强密码:至少8位,含大小写和数字
password_re = r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[\w!@#$%^&*]{8,}$'
# IPv4地址
ip_re = r'^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$'
python复制# 提取Markdown链接
text = "Visit [Google](https://google.com) or [Baidu](https://baidu.com)"
links = re.findall(r'\[(.*?)\]\((.*?)\)', text)
# 结果:[('Google', 'https://google.com'), ('Baidu', 'https://baidu.com')]
# 驼峰转下划线
def camel_to_snake(name):
return re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
# "MyVariableName" → "my_variable_name"
python复制# 优化前:可能产生大量回溯
slow_re = r'(\w+)*=(\w+)'
# 优化后:使用原子分组
fast_re = r'(?>\w+)*=(\w+)'
python复制# 独占模式(Python 3.11+)
best_re = r'\w++\d' # 第一个+是独占量词
python复制# 匹配特定前缀的字符串
optimized_re = r'^(?=.*special).*target' # 先检查包含'special'
掌握正则表达式就像获得文本处理的超能力——它能让复杂的字符串操作变得简单高效。在实际项目中,我习惯将常用正则模式集中管理,配合单元测试确保其准确性。当遇到特别复杂的匹配需求时,不妨拆分成多个简单正则分步处理,这往往比编写一个"万能"表达式更可靠。