如何从匹配f-string模板的格式化字符串中通用提取变量值?
如何从f-string模板和生成的字符串中通用提取变量值
给定一个无格式化指令的f-string风格模板(例如"{kid} ate {number} {fruit}"),以及完全匹配该模板生成的字符串(例如"Jack ate 42 apples"),需要通用地提取每个模板变量对应的内容,无需提前硬编码变量名,且支持任意数量的变量。
方案1:将模板转换为正则表达式(最通用)
通过解析f-string模板,自动生成带命名捕获组的正则表达式,再匹配目标字符串提取变量值。该方法能处理模板中的正则特殊字符,且无需提前知晓变量名。
import re def extract_vars_from_template(template: str, target: str) -> dict: # 转义模板中的正则特殊字符,保留{}的原始格式 escaped_template = re.escape(template).replace(r'\{', '{').replace(r'\}', '}') # 将{变量名}替换为正则命名捕获组,使用非贪婪匹配避免跨变量匹配 regex_pattern = re.sub(r'\{(\w+)\}', r'(?P<\1>.+?)', escaped_template) # 完全匹配目标字符串 match_result = re.fullmatch(regex_pattern, target) return match_result.groupdict() if match_result else {} # 测试示例 template = "{kid} ate {number} {fruit}" example = "Jack ate 42 apples" print(extract_vars_from_template(template, example)) # 输出: {'kid': 'Jack', 'number': '42', 'fruit': 'apples'}
优势
- 自动识别模板中的所有变量名,无需提前定义
- 支持模板包含正则特殊字符(例如模板为
"User {id} has {count} points.",生成字符串为"User 123 has 99 points."也能正确提取) - 非贪婪匹配确保变量值不会包含后续的固定模板片段
方案2:基于固定片段分割字符串(无正则依赖)
通过拆分模板得到固定文本片段和变量名列表,再用固定片段分割目标字符串,直接得到对应变量的值。该方法逻辑直观,适合简单场景。
import re def extract_vars_from_template(template: str, target: str) -> dict: # 拆分模板为固定片段和变量名列表 template_parts = re.split(r'\{(\w+)\}', template) fixed_segments = template_parts[::2] # 偶数位置是固定文本 var_names = template_parts[1::2] # 奇数位置是变量名 extracted = {} current_str = target for idx, var in enumerate(var_names): # 用下一个固定片段拆分当前字符串,获取变量值 if idx + 1 < len(fixed_segments): var_value, current_str = current_str.split(fixed_segments[idx+1], 1) else: var_value = current_str extracted[var] = var_value return extracted # 测试示例 template = "{kid} ate {number} {fruit}" example = "Jack ate 42 apples" print(extract_vars_from_template(template, example)) # 输出: {'kid': 'Jack', 'number': '42', 'fruit': 'apples'}
优势
- 无需复杂正则,代码逻辑易读
- 同样自动识别变量名,通用性较强
原有代码的问题
你提供的实现需要提前硬编码所有变量名,且会错误地将模板中的其他变量占位符(例如{number})当作固定文本进行替换,导致变量值提取错误(例如模板包含多个变量时,替换逻辑会失效)。上述两种方案均解决了这些问题,实现了真正的通用性。
内容的提问来源于stack exchange,提问作者Clay
相关产品推荐
相关产品推荐

