解法
解析现实文本往往需要一个正则来识别结构化项目——如 H1 或 (AH2b+EUH3) 这样的代码——并捕获其后的消息。写成一行时,该模式就变成一堵密集的标点墙:嵌套组、前瞻和量词没有注释空间,每次改动都要解开整个字符串。明显的修复方法各有代价:保留单行,每次编辑都有风险;手写详细模式,子模式会在其出现的地方重复;添加构建正则可用的库,就得学习新语法和依赖。
做法是把模式当作代码。作者一次定义每个逻辑单元——一个代码片段如 [A-Z]*H,多代码包装由加号分隔的代码,然后是完整匹配器——每个都是带有逐行注释的原始详细字符串,通过 {code} 占位符从较小模式组合较大模式。因为 re.VERBOSE 忽略空白和井号注释,每个片段自上而下可读:括号和交替变成可见的结构,而不是字符汤。因为 f-string 在构建时解析,传给 re 模块的仍是一个普通模式字符串。
好处恰好出现在单行正则的痛点:每个片段只定义一次,语法变更会更新所有嵌入了它的模式;片段可以在拼接前独立用 re.findall 测试;且不增加新东西——作者使用了两个长期共存的标准库特性,并承认用了三年才看到这种组合。文章记录了陷阱:井号和空格需要转义或字符类,f-string 中花括号量词必须双写,内联的 (?x) 标志在调用者控制标志时保持详细模式有效。
What it achieved
像写代码一样组织正则:把每个片段定义为带注释的详细字符串,再用 f-string 组合成最终模式。
为什么有效
re.VERBOSE 本就忽略空白和注释,所以每个片段读起来像带注释的代码,仅用标准库。
f-string 插值在构建时拼接片段,留下普通模式字符串,所有 re 调用无需改变即接受。
每个片段只定义一次,语法变更会更新每个组合模式,而不是重复内联副本。
片段在组合前可独立测试,所以失败点可以定位到片段间的连接处。
零依赖且无新 DSL,该方法可扩展到任何 Python 3.6+ 代码库,无需设置。
可以借鉴什么
当一个模式难以维护时,不要添加库:组合你已有的特性——详细注释提高可读性,插值实现复用——零依赖。
后续
这篇文章于 2022 年 5 月发布,在 Hacker News 上获得 304 分和 90 条评论;反应分为两类:一些人视其为启示,另一些人指出将正则拆分为可复用的子模式已是常见做法。评论者指出更强的机制——PCRE 和 Perl 的 DEFINE 子程序块,以及第三方 regex 模块——用于不依赖插值的复用,作者附录了用 DEFINE 实现同一解析器的部分。文章仍然在线,记录了这些注意事项,核心主张保持不变:零依赖、可组合、带注释的模式。
从这里,追溯依据
参考来源
- The unreasonable effectiveness of f-strings and re.VERBOSE death.andgravity.com
- The unreasonable effectiveness of f-strings and re.verbose — Hacker News discussion news.ycombinator.com