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

8

我想捕获一个嵌套结构的内部。

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 );
}

由于捕获组和捕获标记都似乎不起作用,除非将其即时分配给变量。然而,这会创建一个额外的标记,我真的希望避免。

所以有两个问题:

  • 如何使捕获标记在嵌套结构中正常工作?
  • 是否有一种使用捕获组或捕获标记在标记中获取嵌套结构内部的方法?

1
这种情况有何可怕之处...你不知道问题所在,这似乎有点过分了?另外,你尝试运行发布的代码以查看是否编译通过了吗(它没有)?无论如何,你的语法应该是 '(' ~ ')' [<( .+? )>] - ugexe
1
它被分割了;如果你把它们一起发布,它就会出现。为了澄清而添加。另外,为什么需要在这里使用非捕获组? - jjmerelo
1个回答

6

两个问题的一个解决方案

  • 根据ugexe的评论,[...] 组合结构适用于你所有的使用情况。

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

  • (...) 捕获/组合结构将节约匹配限制为最小匹配,当棘轮生效时。像:r (.+?)这样的模式永远不会匹配多于一个字符。

上述最后两个要点所描述的行为并不明显,也没有在文档中提到,可能与设计文档不符,可能是烤漏洞,可能只是我的想象等。本回答的其余部分将解释我对上述三种情况的发现,并讨论一些可以做的事情。
作为完美的说明,好像所有的东西都很正常。

<()>是捕获标记。
它们表现为零宽度断言。每个断言“这标志着我希望对包含此标记的正则表达式进行捕获的开始/结束位置”。
根据正则表达式~运算符的文档说明:
它大多忽略左边参数,并操作接下来的两个[参数](实际上它会操作接下来的两个原子或组)。
在正则表达式模式"(" ~ ")" <(\w)>中:
- ")"~后的第一个原子/组。 - <(~后的第二个原子/组。 - ~忽略\w)>
解决方案是使用 [...]:
say '(a)' ~~ / '(' ~ ')' [ <( \w )> ] /; # 「a」

同样,在语法中:
token TOP { '(' ~ ')' [ <( .+? )> ] }

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

  • 它可能不是您想要的。它会创建一个额外的令牌 捕获。而您写道您想避免这种情况。

  • 即使您想要额外的捕获,当 ratchet 生效时使用 (...) 会夹紧括号内的节俭匹配。

关于捕获标记“不起作用”的解决方法?

我认为更新文档是最好的做法。但是我认为,无论谁想要提交有关此问题的问题或准备 PR,都应该利用以下内容。

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

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

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

<(标记表示匹配的整个捕获的开始,而相应的)>标记表示其结束点。当匹配成功时,它们表现为始终为真的断言,但具有设置匹配对象的.from.to属性的副作用。

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

目前为止,在所有GH搜索<()>都没有结果,但这是由于当前内置的GH搜索的弱点,而不是因为这些存储库中没有任何内容,例如this


我很好奇,于是尝试了这个:
my $str = "aaa";
say $str ~~ / <(...)>* /;

它无限循环。星号仅作用于">"后的")"。这证实了捕获标记被视为原子的意义。
正则表达式中的~运算符适用于[...]和其他一些分组原子结构。解析它们中的任何一个都有一个在正则表达式模式内的开始和结束。
捕获标记不同之处在于它们不一定是成对的,开始或结束可以是隐式的。
也许这使得像我们希望的那样处理它们对于Raku来说变得不合理地困难,因为开始(/{)和结束(/})出现在俚语边界上,而Raku是单遍解析braid

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

如果正则表达式是唯一关心左右捕获标记的正则表达式构造,那么在正则表达式部分提到这个问题可能是最好的选择。

但考虑到多个正则表达式构造关心(如上述无限循环示例中的限定符),那么也许最好的地方是捕获标记部分。

或者最好在两者中都提到。(尽管这是一个棘手的问题...)

:r (.*?)的问题应该怎么办?

我认为更新文档是最好的选择。但我认为,无论谁想要提交一个问题或准备PR,都应该充分利用以下内容。

这是已知的预期行为还是一个错误?

搜索ratchet frugal的GH repos:

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

上述搜索是针对这两个单词的。分别搜索可能会揭示重要的相关提及,而这些提及可能不包括另一个单词。

在撰写本文时,所有搜索.*?或类似内容的GH搜索都没有结果,但这是当前内置GH搜索的一个弱点,而不是这些存储库中没有任何内容。
也许这里的问题不仅限于“ratchet”、“frugal”和“capture”的组合?
也许可以使用“ratchet”、“frugal”和“capture”这些词来提交一个问题?

进行了编辑以澄清。仍然不清楚为什么 H 不起作用。原子化在起始括号处停止,分组实际上并没有起作用。 - jjmerelo
1
回答这个 Stack Overflow 的问题让我想到了一种简单的技巧,可以捕获多个匹配项中的最后一个匹配项。或许这很显然,但以防万一还是在这个评论里写下来,添加到我们共同的 Stack Overflow 知识库中:my $str = "aaa"; say $str ~~ / [<(\w)>]* /; # 「a」. - raiph
1
@jjmerelo 在您发布评论之前,您已经接受了。那时我的回答意外地隐藏了 H 的问题(我当时没有理解 Rakudo 中实际上有一个看起来像是 bug 的问题;它是一个 bug 吗?您知道对应的已报告问题吗?)并且对您的其他观点做得不好。我在这个答案上的大部分工作都是在您接受之后完成的。明确一下,接受并不是我关心的重点。我的主要目标是为问者、读者、rakuns 和评论者编写有用的答案和评论(偶尔会添加诗歌、问题或其他元素以增加趣味性)。 - raiph
抱歉,你在这里的意思是什么? - jjmerelo
我的意思是,我回答中讨论夹紧的部分。例如,“(...)捕获/分组结构夹紧...”。更重要的是,您对该部分所涵盖的可能反应有何看法,即如何解决“:r(.*?)无法工作”的问题?。至少,这是一个错误(我认为是这样),您是否知道相应的已提交问题? - raiph
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接