python sub一次性替换

问题来源

字符串一次替换,为什么不能多次替换呢,例如

1
2
3
4
5
6
s = """
<xml>
<field name="SALARYCATALOG_ID">150</field>
<field name="SALARYCATALOG_ID">170</field>
</xml>
"""

假设150要被替换成170,而170要被替换成190,如果for循环的话,

1
2
3

s.replace('<field name="SALARYCATALOG_ID">150</field>', '<field name="SALARYCATALOG_ID">170</field>') # 第一次
s.replace('<field name="SALARYCATALOG_ID">170</field>', '<field name="SALARYCATALOG_ID">190</field>') # 第二次

就会导致结果出现偏差,整个字符串都会变成190,那么应该有种方法,可以一次性的匹配完并且返回结果。

解决方式

关于re.sub.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from typing import Dict
import re


def retrieve_formula(old_formula: str, field_mapping: Dict):
regexp = re.compile(
r'<field name="(BUSINESSUNIT_ID|PAYVAR_ID|SALARYCATALOG_ID)">(\d+)</field>'
)

def rep(match_data):
# 自定义的函数,匹配到每次都会走到,然后统一返回
# import ipdb;ipdb.set_trace() # 自行加断点调试
try:
field_name = match_data.group(1)
replaced_id = field_mapping[field_name][match_data.group(2)]
except KeyError:
return match_data.group(0)
except Exception:
return match_data.group(0)
return '<field name="{}">{}</field>'.format(field_name, replaced_id)
return re.sub(regexp, rep, old_formula)

情况一

  1. 没有一处匹配的情况

实际会被匹配到,但是替换值时会触发KeyError,所以返回group(0)

1
2
3
4
5
6
7
8
9
10
formula_1 = """
<xml>
<field name="SALARYCATALOG_ID">150</field>
<field name="BUSINESSUNIT_ID">973</field>
<field name="PAYVAR_ID">256</field>
</xml>
"""
field_mapping = {
"SALARYCATALOG_ID": {},
}
  1. 匹配到一处的情况

由于150会被160替换,所以只有此处不会触发KeyError

1
2
3
4
5
6
7
8
9
10
11
12
13
formula_2 = """
<xml>
<field name="SALARYCATALOG_ID">150</field>
<field name="BUSINESSUNIT_ID">973</field>
<field name="PAYVAR_ID">256</field>
</xml>
"""
field_mapping = {
"SALARYCATALOG_ID": {
"150": "160",
"170": "180",
},
}
  1. 匹配多处的情况,情况一:一个类别出现多次

150会被160替换,170会被180替换,由于sub只走一次,而rep函数会被循环匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

formula_3 = """
<xml>
<field name="SALARYCATALOG_ID">150</field>
<field name="BUSINESSUNIT_ID">973</field>
<field name="PAYVAR_ID">256</field>
<field name="SALARYCATALOG_ID">170</field>
</xml>
"""
field_mapping = {
"SALARYCATALOG_ID": {
"150": "160",
"170": "180",
},
}
  1. 匹配多处的情况,情况二:多次匹配

同理如上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

formula_4 = """
<xml>
<field name="SALARYCATALOG_ID">150</field>
<field name="BUSINESSUNIT_ID">973</field>
<field name="PAYVAR_ID">256</field>
<field name="SALARYCATALOG_ID">170</field>
</xml>
"""
field_mapping = {
"SALARYCATALOG_ID": {
"150": "160",
"170": "180",
},
"BUSINESSUNIT_ID": {
"973": "900",
},
"PAYVAR_ID": {
"256": "300",
},
}

总结

sub可以传函数是一个非常有用的做法,其中rep函数会在sub匹配到多次调用,然后最终sub一次返回,这个非常有用。


版权声明:本文为ox180x原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。