re.sub()中引用捕获组最常用\1、\2等数字形式,命名组用\g更清晰,函数替换通过Match对象的group()方法获取匹配内容。
\1、\2 引用分组最直接匹配后想在替换字符串里复用捕获内容,最常用方式就是用反斜杠加数字:\1 表示第一个括号内的匹配,\2 是第二个,以此类推。这是正则引擎原生支持的语法,无需额外函数。
注意:数字只认 () 捕获组,不认 (?:...) 非捕获组;且编号从左到右按开括号顺序算,嵌套也一样。
re.sub(r"(\w+)@(\w+\.\w+)", r"[\1] at [\2]", "user@example.com") → "[user] at [example.com]"
r"\0",它代表整个匹配(等价于 re.sub(..., r"\g", ...)),但容易和八进制转义混淆,不建议用r"C:\\temp\\file.txt",否则 \t 会被解释为制表符\g 按命名组引用更清晰当正则里有多个括号、逻辑复杂时,靠数 \1 \2 容易错。改用命名捕获组 + \g 语法,可读性和维护性高得多。
(?P...) ,比如 r"(?P\d{4})-(?P\d{2})"
r"\g/\g" ,比 r"\1/\2" 直观得多\g
\g 依然表示整个匹配,和 \0 不同,它不会被误解析为字符编码
Match 对象取 .group()
当替换逻辑不能靠静态字符串搞定(比如要转大小写、查表、条件判断),就得传一个函数给 re.sub()。函数接收一个 re.Match 对象,从中调用 .group(1)、.group("name") 等方法取值。
def replacer(match: re.Match) -> str:,返回替换后的字符串match.group(0) 是整个匹配,match.group(1) 是第一捕获组,match.group("city") 是命名组? 修饰且没出现),.group() 会抛 IndexError,要用 .groupdict().get("name", "") 更安全re.sub(r"(\d+)", lambda m: str(int(m.group(1)) * 2), "a1b3c5") → "a2b6c10"
看似简单,实际踩坑不少。几个高

"\1"(普通双引号字符串)可能出错——Python 会先尝试把 \1 当 ASCII 控制字符处理。务必用原始字符串 r"\1"
r"a*")会导致无限循环替换,re.sub() 内部会跳过空匹配,但逻辑仍需警惕re.U 标志(Python 3 默认开启,但显式写上更稳妥),否则 \w 可能不匹配汉字r"\1...\2";复杂逻辑才上函数真正难的不是语法,而是写对正则本身——组怎么括、要不要非贪婪、边界怎么锚定。引用只是“最后一公里”,前面没匹配准,后面全白搭。