捕获正则表达式或语法标记中嵌套结构内的内容

Capturing what's inside a nested structure in a regex or grammar token

我想拍摄 nested structure 的内部。

my $str = "(a)";
say $str ~~ /"(" ~ ")" (\w) /;
say $str ~~ /"(" ~ ")" <(\w)> /;
say $str ~~ /"(" <(~)> ")" \w /;
say $str ~~ /"(" <(~ ")" \w /;

第一个有效;最后一个有效,但也捕获了右括号。其他两个失败了,所以在这种情况下不可能使用捕获标记。但问题在语法上下文中更为复杂,因为捕获组似乎也不起作用,如下所示:

# Please paste this together with the code above so that it compiles.
grammar G {
    token TOP {
              '(' ~ ')' $<content> = .+?
    }
}

grammar H {
    token TOP {
              '(' ~ ')' (.+?)
    }
}

grammar I {
    token TOP {
              '(' ~ ')' <( .+? )>
    }
}

$str = "(one of us)";
for G,H,I -> $grammar {
    say $grammar.parse( $str );
}

因为捕获分组或 capture markers 似乎都不起作用,除非它被动态分配给一个变量。然而,这会创建一个我非常想避免的额外标记。 所以有两个问题

一个解决两个问题

  • 根据 ugexe 的评论,[...] 分组结构适用于您的所有用例。

  • <()> 捕获标记不是分组结构,因此它们不能与正则表达式 ~ 操作一起使用,除非它们被分组。

  • (...)capture/grouping 结构限制 frugal matching to its minimum match when ratchet 生效。像 :r (.+?) 这样的模式永远不会匹配一个以上的字符。

上面最后两个要点中描述的行为并不明显,不在文档中,可能与设计文档不符,可能是漏洞百出,可能是我的想象,等等。这个答案的其余部分解释了我对上述三个案例的发现,并讨论了一些可以做的事情。

油嘴滑舌的解释,好像全是废话

<()>capture markers

它们表现为零宽度断言。每个断言“这标记了我想要捕获到 start/end 的位置,用于包含此标记的正则表达式”。


根据正则表达式 ~ 运算符的文档:

it mostly ignores the left argument, and operates on the next two [arguments]

(文档在我写“参数”的地方说“原子”。实际上它对接下来的两个原子或组进行操作。)

在正则表达式模式中 "(" ~ ")" <(\w)>:

  • ")"~之后的第一个atom/group。

  • <(~.

    之后的第二个 atom/group
  • ~ 忽略 \w)>.


解决方法是使用[...]:

say '(a)' ~~ / '(' ~ ')' [ <( \w )> ] /; # 「a」

同样,在语法中:

token TOP { '(' ~ ')' [ <( .+? )> ] }

(...) 分组不是您想要的,原因有二:

  • 这不可能是你想要的。它将创建一个额外的 token capture。你写道你想避免这种情况。

  • 即使您想要额外的捕获,当棘轮有效时使用 (...) 会限制括号内的节俭匹配。

捕获标记“不起作用”可以做些什么?

我认为文档更新可能是最好的选择。但是 imo 任何想提出问题或准备 PR 的人,最好使用以下内容。

已知这是有意为之的行为还是错误?

GH 存储库中“捕获标记”的搜索次数:

术语“捕获标记”来自文档,而不是旧的设计文档,它只是说:

A <( token indicates the start of the match's overall capture, while the corresponding )> token indicates its endpoint. When matched, these behave as assertions that are always true, but have the side effect of setting the .from and .to attributes of the match object.

(也许您可以从中找出要在问题等中搜索的字符串...)

在撰写本文时,所有 GH 搜索 <()> 都是空白,但这是由于当前内置 GH 搜索的弱点,而不是因为没有任何那些回购协议,例如 this.


我很好奇并尝试了这个:

my $str = "aaa";
say $str ~~ / <(...)>* /;

无限循环。 * 仅作用于 )>。这证实了捕获标记被视为原子的意义。


正则表达式 ~ 运算符适用于 [...] 和其他一些分组原子结构。解析它们中的任何一个都有一个开始和结束一个正则表达式模式中。

捕获标记的不同之处在于它们不一定成对出现——开始或结束可以是隐式的。

考虑到开始(/{)和结束(/})发生,也许这使得我们对 Raku 的处理变得异常困难在俚语边界和 Raku 是单程解析 braid?


我认为文档修复可能是对您的 SO 的捕获标记方面的适当响应。

如果正则表达式 ~ 是唯一关心左右捕获标记都是一个单独原子的正则表达式构造,那么提及此问题的最佳位置可能是在正则表达式 ~ 部分.

但是考虑到多个正则表达式构造关心(量词按照上面的无限循环示例执行),那么最好的地方可能是捕获标记部分。

或者最好在两者中都提到。 (虽然那是个滑坡...)

:r (.*?)“不工作”可以做些什么?

我认为文档更新可能是最好的选择。但是 imo 任何想提出问题或准备 PR 的人,最好使用以下内容。

已知这是有意为之的行为还是错误?

ratchet frugal 的 GH 回购搜索:

术语“ratchet”和“frugal”都来自旧的设计文档,并且仍在最新的文档中使用,而且似乎没有别名。因此,搜索它们应该与所有相关提及相匹配。

以上搜索都是针对这两个词的。一次搜索一个可能会发现恰好没有提及另一个的重要相关提及。

在撰写本文时,所有 GH 搜索 .*? 或类似的绘图空白,但这是由于当前内置 GH 搜索的弱点,而不是因为这些存储库中没有任何内容。


也许这里的问题比棘轮、节俭和捕获的组合更广泛?

也许使用“ratchet”、“frugal”和“capture”这些词来提交问题?