pin_drop当前位置:知识文库 ❯ 图文
Python re.sub详解 - 正则替换与回调函数实战
一、概述
re.sub() 是 Python re 模块中最常用的函数之一,用于执行正则表达式替换操作。它能够查找字符串中所有匹配正则表达式模式的部分,并将其替换为指定的字符串或通过回调函数动态生成的内容。
与 Python 内置的 str.replace() 方法不同,re.sub() 支持正则表达式,因此可以实现更灵活、更强大的替换逻辑。同时,它还支持回调函数(Callable)作为替换参数,使得每次替换都可以根据匹配内容动态计算替换值。
二、语法与参数
re.sub() 的函数签名如下:
代码示例
re.sub(pattern, repl, string, count=0, flags=0)参数说明
-
pattern:正则表达式模式,定义要匹配的内容
-
repl:替换字符串或回调函数。字符串中可以使用
\1、\g等反向引用 -
string:待处理的原始字符串
-
count:可选参数,指定最大替换次数。默认
0表示替换所有匹配 -
flags:可选的标志位,控制匹配行为(如
re.IGNORECASE)
返回值
返回替换后的新字符串。原始字符串不会被修改(字符串在 Python 中是不可变的)。如果没有匹配项,则返回原始字符串的副本。
三、基本用法
最简单的用法是将匹配到的内容替换为一个固定字符串:
代码示例
import re
text = "Hello World! Welcome to the World of Python."
# 将所有 "World" 替换为 "Python"
result = re.sub(r'World', 'Python', text)
print(result)
# 输出: Hello Python! Welcome to the Python of Python.
使用 count 参数控制替换次数:
代码示例
import re
text = "apple banana apple orange apple"
# 只替换前2个 "apple"
result = re.sub(r'apple', 'fruit', text, count=2)
print(result)
# 输出: fruit banana fruit orange apple四、代码示例
示例1:使用反向引用交换单词顺序
代码示例
import re
text = "张三 李四 王五"
# 使用捕获分组和反向引用交换两个相邻单词
result = re.sub(r'(\w+)\s+(\w+)', r'\2 \1', text)
print(result)
# 输出: 李四 张三 王五
# 使用命名分组
result2 = re.sub(r'(?P<first>\w+)\s+(?P<second>\w+)', r'\g<second> \g<first>', text)
print(result2)
# 输出: 李四 张三 王五示例2:格式化电话号码
代码示例
import re
phones = "13812345678, 15987654321, 18600001111"
# 将11位手机号格式化为 XXX-XXXX-XXXX
result = re.sub(r'(\d{3})(\d{4})(\d{4})', r'\1-\2-\3', phones)
print(result)
# 输出: 138-1234-5678, 159-8765-4321, 186-0000-1111示例3:清理HTML标签
代码示例
import re
html = "<p>这是一段<b>重要</b>的文本,包含<a href='#'>链接</a>。</p>"
# 移除所有HTML标签
clean_text = re.sub(r'<[^>]+>', '', html)
print(clean_text)
# 输出: 这是一段重要的文本,包含链接。示例4:敏感词过滤
代码示例
import re
text = "这个产品非常垃圾,客服态度很差,真是坑爹"
# 敏感词列表
sensitive_words = ['垃圾', '坑爹', '扯淡']
# 构建正则表达式模式
pattern = '|'.join(re.escape(w) for w in sensitive_words)
# 替换为等长的星号
result = re.sub(pattern, lambda m: '*' * len(m.group()), text)
print(result)
# 输出: 这个产品非常**,客服态度很差,真是**五、回调函数高级用法
re.sub() 最强大的功能之一是支持使用回调函数作为 repl 参数。回调函数接收一个 Match 对象作为参数,并返回替换后的字符串。这使得替换逻辑可以非常灵活。
示例5:将匹配的数字翻倍
代码示例
import re
text = "价格分别是 10元、20元 和 30元"
def double_number(match):
num = int(match.group())
return str(num * 2)
result = re.sub(r'\d+', double_number, text)
print(result)
# 输出: 价格分别是 20元、40元 和 60元示例6:驼峰命名转换
代码示例
import re
def to_camel_case(match):
"""将下划线分隔的单词转换为驼峰命名"""
word = match.group()
return word[0].upper() + word[1:].lower()
text = "hello_world_python_programming"
# 匹配 _x 形式的内容并转换
result = re.sub(r'_([a-z])', lambda m: m.group(1).upper(), text)
print(result)
# 输出: helloWorldPythonProgramming示例7:Markdown链接转HTML
代码示例
import re
markdown = "访问 [Python官网](https://www.python.org) 和 [GitHub](https://github.com)"
def md_link_to_html(match):
text = match.group(1)
url = match.group(2)
return f'<a href="{url}">{text}</a>'
result = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', md_link_to_html, markdown)
print(result)
# 输出: 访问 <a href="https://www.python.org">Python官网</a> 和 <a href="https://github.com">GitHub</a>示例8:带计数器功能的替换
代码示例
import re
text = "错误日志: error1, error2, error3"
counter = [0] # 使用列表实现闭包中的可变状态
def numbered_replacement(match):
counter[0] += 1
return f"错误#{counter[0]}"
result = re.sub(r'error\d+', numbered_replacement, text)
print(result)
# 输出: 错误日志: 错误#1, 错误#2, 错误#3六、注意事项
注意1:反向引用的转义问题:在替换字符串中使用
\1、\2等反向引用时,建议使用原始字符串(r'\1'),避免 Python 将\1解释为字符转义。对于编号大于 9 的分组,必须使用\g格式。
代码示例
import re
text = "abc123def"
# 使用原始字符串(推荐)
result = re.sub(r'([a-z]+)(\d+)', r'\2-\1', text)
print(result) # 输出: 123-abc
# 使用 \g<n> 格式处理分组编号大于9的情况
# 注意: \g<10> 不能写成 \10 (会被解析为 \1 + "0")注意2:替换字符串中的特殊字符:在替换字符串中,
&和\有特殊含义。如果需要替换为包含这些字符的字面值,需要使用re.escape()或使用回调函数。
最佳实践:频繁使用时预编译正则:如果同一个正则表达式模式会被多次用于
re.sub()调用,建议使用re.compile()预编译,然后使用pattern.sub()方法,可以提升性能。
代码示例
import re
# 不推荐:每次都重新编译
for text in large_list:
result = re.sub(r'\d+', 'NUM', text)
# 推荐:预编译后复用
pattern = re.compile(r'\d+')
for text in large_list:
result = pattern.sub('NUM', text)小贴士
re.sub() 还有一个"隐藏"功能:它会同时返回替换次数。使用 re.subn() 函数可以获取一个元组 (替换后字符串, 替换次数),这在需要知道有多少处被替换时非常有用。
七、小结
-
基础替换:使用字符串或反向引用
\1、\g进行替换 -
次数控制:通过
count参数限制最大替换次数 -
回调函数:使用函数作为 repl 参数,实现动态、条件化替换逻辑
-
性能优化:频繁使用时使用
re.compile()预编译正则表达式
八、练习题
练习1:日期格式转换
编写一个程序,使用 re.sub() 将文本中所有 YYYY-MM-DD 格式的日期转换为 DD/MM/YYYY 格式。例如 "2025-06-07" 转换为 "07/06/2025"。
练习2:实现简单的模板引擎
编写一个函数 render_template(template, context),使用 re.sub() 和回调函数将模板中的 {{variable}} 占位符替换为 context 字典中对应的值。
代码示例
template = "Hello {{name}}, your age is {{age}}."
context = {"name": "Alice", "age": 30}
# 期望输出: "Hello Alice, your age is 30."练习3:CSS属性名转换
编写程序使用 re.sub() 将 CSS 属性名从连字符格式(kebab-case)转换为驼峰格式(camelCase)。例如 font-size 转换为 fontSize,background-color 转换为 backgroundColor。
九、常见问题
常见问题
re.sub() 和 str.replace() 有什么区别?
str.replace() 只能进行固定字符串替换,不支持模式匹配。re.sub() 支持正则表达式,可以进行复杂的模式匹配替换,还支持回调函数和反向引用。如果只是简单字符串替换,str.replace() 更快更简单;如果需要模式匹配,则用 re.sub()。
回调函数中的 Match 对象有哪些常用方法?
常用方法包括:.group() 或 .group(0) 获取完整匹配文本,.group(1)、.group(2) 等获取捕获分组,.start() 获取匹配起始位置,.end() 获取匹配结束位置,.span() 返回 (start, end) 元组。在回调函数中最常用的是 .group()。
re.sub() 会修改原始字符串吗?
不会。Python 中的字符串是不可变对象,re.sub() 返回的是一个新字符串,原始字符串保持不变。如果需要保存替换结果,必须将返回值赋值给变量。
如何同时替换多个不同的模式?
可以使用 | 运算符将多个模式组合成一个正则表达式,然后在回调函数中根据不同匹配内容进行不同处理。例如:re.sub(r'pattern1|pattern2|pattern3', callback, text),在 callback 中通过 match.group() 判断是哪个模式匹配到的。
re.subn() 和 re.sub() 的区别是什么?
re.subn() 与 re.sub() 功能完全相同,但返回值不同。re.sub() 只返回替换后的字符串,而 re.subn() 返回一个元组 (替换后的字符串, 替换次数)。当你需要知道实际发生了多少次替换时,使用 re.subn() 更方便。
本文涉及AI创作
内容由AI创作,请仔细甄别