
本文详解如何使用 Python 正则表达式匹配形如 identifier{...} 中的花括号内内容,特别处理内部允许存在 {{var}} 但禁止嵌套 {} 的场景,避免贪婪/懒惰匹配导致的截断或跨段合并问题。
本文详解如何使用 python 正则表达式匹配形如 `identifier{...}` 中的花括号内内容,特别处理内部允许存在 `{{var}}` 但禁止嵌套 `{}` 的场景,避免贪婪/懒惰匹配导致的截断或跨段合并问题。
在文本处理中,常需提取类似 identifier{...} 结构中花括号内的内容,但标准懒惰匹配 r'\{.*?\}' 在遇到内部 {{var}} 时极易失效:.*? 会过早匹配到第一个 },或贪婪模式下吞并多个闭合 },造成错误分组。根本挑战在于——{ 和 } 既是外层定界符,又可能作为 {{var}} 的组成部分出现,必须区分“结构边界”与“字面字符”。
✅ 推荐方案:基于字符排除的稳健匹配
核心思路是禁止外层 { 和 } 出现在内容主体中,仅允许 {{...}} 作为特例存在。以下正则精准实现该逻辑:
import re
pattern = r"{([^{}]*(?:{{[^{}]*}}[^{}]*)*)}"
content = "identifier{ {{var1}} rest of the content} outer content identifier{ {{var2}} another content} identifier{ content with no vars }"
matches = re.findall(pattern, content)
result = [s.strip() for s in matches]
print(result)
# 输出: ['{{var1}} rest of the content', '{{var2}} another content', 'content with no vars']? 模式解析:
- { —— 字面匹配左大括号(外层起始)
- ( —— 开始捕获组(目标内容)
- [^{}]* —— 匹配零或多个非 {、非 } 字符(基础文本)
- (?:{{[^{}]*}}[^{}]*)* —— 非捕获组,可重复零次或多次:
- {{ —— 字面匹配双左花括号
- [^{}]* —— 匹配内部变量名(如 var1),不允许含 { 或 }
- }} —— 字面匹配双右花括号
- [^{}]* —— 匹配 }} 后的普通文本(仍禁止 {/})
- ) —— 结束捕获组
- } —— 字面匹配右大括号(外层结束)
⚠️ 注意:此模式严格禁止任何单层 { 或 } 出现在外层括号内,确保结构安全。若业务允许更复杂嵌套(如 {{{var}}}),需改用递归正则(re 不支持,需 regex 库)。
? 进阶限制:避免误匹配孤立花括号
若文本中可能存在独立 { 或 }(非 identifier{...} 结构),可用负向断言增强鲁棒性:
# 更严格的版本:确保 { 前无 {,} 后无 }
strict_pattern = r"(?<!{){\s*([^{}]*(?:{{[^{}]+}}[^{}]*)*)\s*}(?!})"
# 使用方式相同,仅替换 pattern 变量该写法通过 (?
? 总结建议
- *优先使用 `[^{}]构建“白名单”逻辑**,比依赖.*?` 更可靠;
- strip() 处理首尾空格是实用惯例,建议统一应用;
- 测试时务必覆盖边界用例:空内容 identifier{ }、纯变量 identifier{{{var}}}、混合文本 identifier{before{{var}}after};
- 若需支持任意深度嵌套(如 {{{a}}}),Python 标准 re 模块无法胜任,应切换至第三方库 regex 并启用 (?R) 递归语法。
此方案兼顾可读性、性能与准确性,是处理模板类文本(如 Jinja、Handlebars 子集)中花括号提取的工业级实践。

















