【问题标题】:Capturing what's inside a nested structure in a regex or grammar token在正则表达式或语法标记中捕获嵌套结构内的内容
【发布时间】:2020-07-04 11:59:36
【问题描述】:

我想捕捉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 似乎都不起作用,除非它被动态分配给变量。但是,这会创建一个我非常想避免的额外令牌。 所以有两个问题

  • 使捕获标记在嵌套结构中起作用的正确方法是什么?
  • 有没有办法使用捕获组或捕获标记中的标记来获取嵌套结构的内部?

【问题讨论】:

  • 这种情况有什么可怕的......你不知道问题,所以看起来有点多?另外,您是否尝试过运行发布的代码以查看它是否可以编译(它没有)?不管怎样,你的语法我应该是'(' ~ ')' [&lt;( .+? )&gt;]
  • 它是分裂的;如果您将它们一起发布,则可以。为澄清而添加。另外,为什么这里需要使用非捕获石斑鱼?

标签: regex grammar raku


【解决方案1】:

两个问题的一个解决方案

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

  • &lt;()&gt; 捕获标记不是分组构造,因此除非它们被分组,否则它们不能与正则表达式 ~ 操作一起使用。

  • (...) 捕获/分组构造将frugal matching 限制在ratchet 生效时的最小匹配。像:r (.+?) 这样的模式永远不会匹配多个字符。

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

花言巧语的解释,仿佛一切都完美无缺

&lt;()&gt;capture markers

它们表现为零宽度断言。每个都断言“这标志着我想要为包含此标记的正则表达式捕获开始/结束的位置”。


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

它主要忽略左边的参数,并对接下来的两个[参数]进行操作

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

在正则表达式模式"(" ~ ")" &lt;(\w)&gt;:

  • ")"~ 之后的第一个原子/组。

  • &lt;(~ 之后的第二个原子/组。

  • ~ 忽略 \w)&gt;


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

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

同样,在语法中:

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

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

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

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

捕获标记“不起作用”该怎么办?

我认为更新文档可能是最好的选择。但是我建议任何想要提交关于一个问题或准备 PR 的人都可以使用以下内容。

已知是预期行为还是错误?

在 GH 存储库中搜索“捕获标记”:

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

&lt;( 标记表示匹配整体捕获的开始,而相应的)&gt; 标记表示其端点。匹配时,这些行为表现为始终为真的断言,但具有设置匹配对象的.from.to 属性的副作用。

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

在撰写本文时,所有 GH 搜索 &lt;()&gt; 都会出现空白,但这是由于当前内置 GH 搜索的弱点,而不是因为这些存储库中没有任何内容,例如 @987654329 @。


我很好奇并尝试了这个:

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

它无限循环。 * 仅作用于 )&gt;。这证实了捕获标记被视为原子的感觉。


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

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

考虑到开始(/{)和结束(/})出现在俚语边界并且 Raku 是单通过解析braid?


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

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

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

或者如果两者都提到它可能会更好。 (虽然那是一个滑坡……)

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

我认为更新文档可能是最好的选择。但是我建议任何想要提交关于一个问题或准备 PR 的人都可以使用以下内容。

已知是预期行为还是错误?

在 GH 存储库中搜索ratchet frugal

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

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

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


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

也许可以使用“ratchet”、“frugal”和“capture”来提交问题?

【讨论】:

  • 进行了编辑以澄清。仍然不清楚为什么 H 不起作用。原子化在起始括号的某处停止,并且分组实际上不起作用。
  • 回答这个 SO 向我建议了一种简单的技术来捕获多个匹配的最后一个匹配。也许这很明显,但万一不是,我在此评论中将其写在这里,以将其添加到我们的集体 SO 知识中:my $str = "aaa"; say $str ~~ / [&lt;(\w)&gt;]* /; # 「a」
  • @jjmerelo 您在发表评论之前接受了。而我当时的回答不小心隐藏了 H 的问题(我不明白 Rakudo 中实际上存在看起来像错误的东西;它是错误吗?你知道相应的提交问题吗?);并且在解决您的其他问题方面做得很差。我在这个答案上的大部分工作都是在您接受它之后完成的。需要明确的是,接受不是我关心的。我的主要目标是为提问者、读者、rakuns 和评论者写有用的答案和 cmets(偶尔会加入诗歌、问题或其他任何东西)。
  • 你做得很好。当我接受它时,我只是不认为你可以让它变得更好,但你做到了,太棒了。
  • @jjmerelo 你对夹紧有什么看法?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多