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 转换为 fontSizebackground-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() 更方便。

标签: re.sub 正则替换 回调函数 Python教程 反向引用 文本处理

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Python re.finditer详解 - 迭代查找正则匹配与Match对象 下一篇: Python re.split详解 - 正则分割字符串与捕获分组

poll相关推荐