Files
stgsharp/future/ngra-regex-sourcegen-goldens.md
T
2026-07-21 18:02:46 +08:00

4.5 KiB
Raw Blame History

NGRA Regex 源生成手写样本

这个文件用于记录源生成器实现前需要手写的正则匹配样本。

流程:

  1. 选一个表达式。
  2. 手写理想匹配代码。
  3. 生成优化后 IR。
  4. 对照手写代码和 IR 段。
  5. 标注每段 IR 应该生成的代码形状。
  6. 抽取生成器规则。

选样原则:

  1. 表达式必须是典型正则写法。
  2. 全部样本合起来应覆盖计划支持的大部分 regex 语法。
  3. 样本不以表达式结构优化为目标,避免依赖公共前缀提取、分支树重排等 AST 优化。
  4. TRY/CONDITION 前缀化改写属于 IR 执行形态整理,不算表达式优化。

记录模板

Regex:

覆盖形态:

期望代码形状:

Optimized IR:

IR -> Code 规则:

备注:

第一批:基础线性匹配与转义

Regex 覆盖形态 手写重点
abc 单个 MATCH_SEQ 最小长度检查、序列匹配、活动指针推进
a[abc]d MATCH_SEQ + MATCH_SET + MATCH_SEQ set 后端展开前的调用边界
[abc] 单个 MATCH_SET 字符集单字符匹配
[.] set 中的字面点号 确认 [.] 和 . 语义分离
. 任意字符匹配 MATCH_SET "." 的特殊后端语义
\. 转义字面点号 确认 \. 进入 seq 系 IR
a\*b 转义操作符字面量 tokenizer 已消解转义语义

第二批:计数

Regex 覆盖形态 手写重点
a* COUNT_SEQ,MIN:0 MAX:-1 贪婪计数、允许空匹配
a+ COUNT_SEQ,MIN:1 MAX:-1 至少一次的计数
a? COUNT_SEQ,MIN:0 MAX:1 可选单元
a{3,5} 固定下限 + 可选上限 下限展开与剩余计数
[abc]* COUNT_SET 字符集循环
.{11,13} 任意字符计数 set 语义在后端展开

第三批:ALT 与前缀化

Regex 覆盖形态 手写重点
`a b` 最小 ALT
`ab cd ef`
`a bc def`
`(ab [cd] .)x`

第四批:复杂计数块

Regex 覆盖形态 手写重点
(ab){2,3} COUNT complex body complex body 调用域、计数退出
`(123(4 5)67){3,4}114514` complex count + ALT + 后缀

第五批:FIND 与 .*

Regex 覆盖形态 手写重点
.*abc 最远/最近搜索前缀 FIND_SEQ 或 FIND_COMPLEX 到后续锚点
abc.* 后缀任意吞吐 尾部 .* 的快速成功策略
[.]* 字面点号计数 不应被当成原装 .* 优化

第六批:字符集语义

Regex 覆盖形态 手写重点
[123abc] 离散字符集 set 后端展开为离散匹配
[1-9] 连续字符集 set 后端展开为范围匹配
\w 转义字符集 escape-set 后端语义
\w+ 转义字符集计数 set 计数循环

第七批:捕获组

Regex 覆盖形态 手写重点
(abc) 普通捕获组 默认序号 group
(?<name>abc) 简单命名组 group 起止范围、PACK
(?<name>.*)234 group 内 .* + 后续锚点 FIND_COMPLEX FURTHEST -1 与后续 MATCH_SEQ
(?<name>.*)a group 内 .* + 单字符锚点 最远搜索回退到后缀匹配
`(?abcd a(bc)c)` group 内 ALT
`a*.[abc]*(?abcd a(bc)c)(?.*)234` 综合样本

当前优先级

第一阶段只要求源生成器能稳定处理:

  1. MATCH_SEQ
  2. MATCH_SET
  3. COUNT_SEQ
  4. COUNT_SET
  5. 简单 ALT
  6. PACK
  7. FIND_SEQ
  8. FIND_COMPLEX COUNT:-1

低优先级:

  1. 逐 region 最短长度断言。
  2. 复杂字符集完全内联。
  3. 公共前缀提取和代码树生成。
  4. 对所有正则语义做完整兼容。

手写代码关注点

每个样本的手写代码都应尽量确认这些点:

  1. 活动指针如何推进。
  2. 失败时是否需要恢复活动指针。
  3. region result 和 single-line result 是否必须分配。
  4. Observe_Line 是否只读取目标行结果。
  5. Observe_Region 是否只读取目标 region 结果。
  6. PACK 使用哪一个成功结果作为捕获区间。
  7. 最小长度检查是否值得在当前样本中生成。