re.sub 使用技巧:捕获分组
1. re.sub
调用格式:
re.sub(pattern, repl, string, count=0, flags=0)
这里记录一下当repl
参数为函数时的使用方法。
方法一:
import re
def dashrepl(matchobj):
if matchobj.group(0) == '-': return ' '
else: return '-'
re.sub('-{1,2}', dashrepl, 'pro----gram-files')
方法二:
import re
dashrepl = lambda x:" " if x.group(0)=="-" else "-"
re.sub('-{1,2}', dashrepl, 'pro----gram-files')
------------------------------ 2020-09-30 更新 ------------------------------
2 关于re.sub 不能如re.findall/match/search 一样捕获分组进行替换或者删除
上样例代码:
import re
s = 'Data: year=2018, monthday=1, month=5, some other text'
reg = r"year=(\d{4}), monthday=(\d{1}), month=(\d{1})"
re.findall:
re.findall(reg,s)
output: [('2018', '1', '5')]
re.sub:
re.sub(reg, "", s)
output: 'Data: , some other text'
由结果可看到:re.sub 替换的是匹配到的所有,在样例中则是包含"year=…"
Stackoverflow 上有说明原因:python re.findall vs re.sub
解决办法:
StackOverflow上有一些解决办法,但是大都不通用或者需要更改你的正则表达式和替换表达式,或者复杂,没有一个通用的方法,故自己一番琢磨后,把解决办法分享出来,如下:
使用上文[1 re.sub](#1 re.sub)的repl方法
def repl(match):
_reg = "|".join(match.groups())
return re.sub(_reg, "",match.group(0)) if _reg else ""
调用:
re.sub(reg,repl, s)
output: 'Data: year=, monthday=, month=, some other text'
注意此方法仅适用于删除, 进阶使用替换的时候,传入替换字符:
r = "我是替换字符"
def repl(match):
_reg = "|".join(match.groups())
return re.sub(_reg, r,match.group(0)) if _reg else r
# 调用
re.sub(reg,repl, s)
output: 'Data: year=我是替换字符, monthday=我是替换字符, month=我是替换字符, some other text'
此方法适用于多分组情况或者无分组情况, 当然如果所有需求里都不会出现 没有分组 的情况时, 可以将末尾的 if _reg else r
去掉,以节省性能,如下:
r = "我是替换字符"
def repl(match):
_reg = "|".join(match.groups())
return re.sub(_reg, r,match.group(0))
# 调用
re.sub(reg,repl, s)
------------------------------ 更新 ------------------------------
如果匹配结果是多行值:上述不奏效,提供一种思路:
如果有一个分组,且分组匹配出来是多行的字符串,这时使用re.sub+str.replace结合:
def repl2(match):
_reg = match.groups()[0]
return match.group(0).replace(_reg, "")