PAYATHON 2026

Raku 中 look-behind 调用预定义 regex 为何结果异常?

数据小许

结论

这段代码反映的是 Rakudo 处理 <?after ...> 中子规则调用时的问题,与 myregex2 和内联正则的匹配意图无关。在相关复现中,<?after <myregex2>> 会让匹配位置多前进一个字符。look-behind 后面紧跟 m 时,这个偏移会影响后续匹配,所以第三、第四次替换的结果不同。相关复现与分析

为什么 myregex1 看起来正常

第一组中,look-behind 后面没有要继续匹配的字符。即使子规则调用导致位置偏移,后面也没有 m 显示出差异,因此两种写法的结果相同。

第二组的内联写法是:

<?after \e\[<[\d;]>*m>

这里的 m 属于 look-behind 的匹配内容。改为调用 <myregex2> 后,look-behind 子规则匹配 \e\[<[\d;]>*m。相关复现显示,子规则形式的 after 会让匹配位置多前进一个字符。问题出在 look-behind 与子规则的交互上,和 ANSI 转义序列本身无关。

规避方式

在当前代码中,可以将 myregex2 的模式直接写在 <?after ...> 中:

my $str = "abc\e[33mdef\e[0mghi";
$str.=subst( / <?after \e\[<[\d;]>*m> /, '***', :g );
say $str; # abc***def***ghi

如果需要复用 myregex2,可以把相关匹配逻辑移出 look-behind,或先用内联模式验证结果。具体改法取决于要替换的文本范围。使用子规则时,应确认它在 <?after ...> 中的行为是否与直接内联相同。

注意事项

这个结论针对题目展示的 Raku/Rakudo 行为。输入没有提供 Rakudo 版本,因此无法判断某个特定版本是否已修复。升级后如果仍使用子规则写法,建议用同一段最小代码确认匹配位置和替换结果。

备注:内容仅供参考。