问题来源
字符串一次替换,为什么不能多次替换呢,例如
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): 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)
|
情况一
- 没有一处匹配的情况
实际会被匹配到,但是替换值时会触发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": {}, }
|
- 匹配到一处的情况
由于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", }, }
|
- 匹配多处的情况,情况一:一个类别出现多次
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 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一次返回,这个非常有用。