Python3 基于正则表达式与字典实现带星号包裹变量的字符串替换问题
我来帮你解决这个变量替换的问题!你的核心需求是不管变量之间有没有空格,都能准确把*包裹的变量替换成字典里对应的值对吧?先说说你之前第二种方法失效的原因——你用了(?<!\*)和(?!\*)这两个断言,意思是变量的前后不能有*,但当变量连在一起时(比如*Day**Subject*),第一个变量的结尾*刚好是第二个变量的开头*,导致第二个变量的前面有*,断言不满足,自然匹配不到。
下面给你两种靠谱的解决方案,都能完美处理有空格和无空格的场景:
方案1:精确匹配字典中的变量(优先匹配长变量)
这个方法会严格只替换字典里存在的变量,而且会优先匹配更长的变量(避免出现类似*FFullName*被拆成*FFirstName*和*Name*的情况):
import re variables = { '*FFullName*': 'Raz Smith', '*FFirstName*': 'Raz', '*FSurname*': 'Smith', '*Subject*': 'hello', '*Day*': '27', } # 注意别用input当变量名,它是Python内置函数 input_with_spaces = '*Day* *Subject* to *FFirstName* *FSurname*' input_without_spaces = '*Day**Subject*to*FFirstName**FSurname*' # 按变量长度降序排序,确保长变量先被匹配 sorted_variable_keys = sorted(variables.keys(), key=lambda x: -len(x)) # 生成匹配所有字典变量的正则表达式 pattern = re.compile('|'.join(re.escape(key) for key in sorted_variable_keys)) # 替换变量 result_with_spaces = pattern.sub(lambda match: variables[match.group()], input_with_spaces) result_without_spaces = pattern.sub(lambda match: variables[match.group()], input_without_spaces) print(result_with_spaces) # 输出: 27 hello to Raz Smith print(result_without_spaces) # 输出: 27hellotoRazSmith
方案2:匹配所有*...*格式的内容(容错性更强)
如果你的输入里可能存在字典中没有的*变量*,想保留这些未定义的变量,用这个方案更合适:
import re variables = { '*FFullName*': 'Raz Smith', '*FFirstName*': 'Raz', '*FSurname*': 'Smith', '*Subject*': 'hello', '*Day*': '27', } input_with_spaces = '*Day* *Subject* to *FFirstName* *FSurname*' input_without_spaces = '*Day**Subject*to*FFirstName**FSurname*' # 匹配所有以*开头和结尾的内容 pattern = re.compile(r'\*[^*]+\*') # 替换存在的变量,不存在的就保留原样 result_with_spaces = pattern.sub(lambda match: variables.get(match.group(), match.group()), input_with_spaces) result_without_spaces = pattern.sub(lambda match: variables.get(match.group(), match.group()), input_without_spaces) print(result_with_spaces) # 输出和方案1一致 print(result_without_spaces) # 输出和方案1一致
关键说明
- 避免内置函数名:别用
input当变量名,它是Python自带的内置函数,容易引发奇怪的问题; - 长变量优先匹配:方案1里对变量按长度降序排序是关键,比如如果字典里同时有
*FFullName*和*FFirstName*,不排序的话会先匹配短的*FFirstName*,导致长变量被拆分; - 去掉多余断言:之前的
(?<!\*)和(?!\*)是画蛇添足,因为我们要匹配的就是*包裹的内容,不需要限制前后有没有*。
内容的提问来源于stack exchange,提问作者squidg
相关产品推荐
相关产品推荐

