针对 Raku 中无限的 <!before> 模式家族的反匹配

Anti-matching against an infinite family of <!before> patterns in Raku

我试图避免匹配字符串末尾的空格,同时仍然匹配单词中间的空格。

这是一个匹配 x 内下划线但不匹配最多三个尾随下划线的正则表达式示例。

say 'x_x___x________' ~~ /
[
| 'x'
| '_' <!before [
        | $ 
        | '_' <?before $> 
        | '_' <?before ['_' <?before $>]>
        | '_' <?before ['_' <?before ['_' <?before $>]>]>
        # ...
    ]>
]+
/;

有没有办法构造 ... 隐含的模式的其余部分?

我建议使用 Capture...,因此:

'x_x___x________' ~~ /(.*?) _* $/; 
say [=10=];     #「x_x___x」

(? 修饰符使 * 'non-greedy'。) 如果我错过了重点,请告诉我!

有点难以辨别您要的是什么。


您可能正在寻找像这样简单的东西:

say 'x_x___x________' ~~ / 'x'+ % '_' ** 1..3 /
# 「x_x___x」

say 'x_x___x________' ~~ / 'x'+ % '_' ** 1..2 /
# 「x_x」

say 'x_x___x________' ~~ / 'x'+ % '_'+ /
# 「x_x___x」

avoid matching whitespace at the end of a string while still matching whitespace in the middle of words

根据 Brad 的回答,以及您对此的评论,如下所示:

/ \w+ % \s+ /

what I'm looking for is a way to match arbitrarily long streams that end with a known pattern

根据@user0721090601 对您的 Q 的评论,以及作为@p6steve 回答的变体,如下所示:

/ \w+ % \s+ )> \s* $ /

The )> capture marker 标记捕获结束的位置。

您可以在该标记的左侧和右侧使用任意图案。

an infinite family of <!before> patterns

推广到任何类型的无限模式系列,无论它们是否 zero-width or not, the most natural solution in a regex is iteration using any of the standard quantifiers 是开放式的。例如,\s+ 表示一个或多个空白字符。[1] [2]

Is there a way to construct the rest of the pattern implied by the ...?

我将其归纳为“Raku 正则表达式中是否有一种方法可以匹配理论上可以被计算机程序识别的任意模式?”

答案总是“是”:

  • 虽然 Raku rules/regexes 可能看起来像传统的正则表达式,但它们实际上是嵌入在您最终可以完全控制的任意程序中的任意函数。

  • 规则对捕获状态具有任意读取权限。[3]

  • 规则可以做任意图灵完备计算[4]

  • rules/regexes的集合可以任意消耗输入并驱动parse/match状态,即可以实现任何解析器。

简而言之,如果用任何编程语言编写的任何程序都可以matched/parsed,则可以matched/parsed使用Rakurules/regexes。

脚注

[1] 如果您使用开放式量词,您需要确保每个匹配项 iteration/recursion消耗至少一个字符,或者失败,从而避免无限循环。例如,即使 * 限定的模式不匹配,量词也会成功,因此请注意不要导致无限循环。

[2] 鉴于您编写示例的方式,也许您对 递归 而不是迭代。可以说,这也很容易做到。[1]

[3] 在 Raku 规则中,捕获形成一个层次结构。有两个特殊变量跟踪此层次结构的两个关键级别的捕获状态:

  • 是最内圈整体捕获的捕获状态。将其视为类似于函数调用堆栈中当前函数调用构造的 return 值。

  • $/是最里面的封闭捕获的捕获状态。将其视为类似于由函数内的特定代码块构造的值。

例如:

'123' ~~ / 1* ( 2* { print "$¢ $/" } ) 3* { print "$¢ $/" } / ; # 1 2123 123
  • 整体/ ... /类似于普通的函数调用。输出的第一个 1 和第一个 123 显示了整个正则表达式捕获的内容。

  • ( ... ) 为正则表达式的一部分设置内部捕获。其中的 2* { print "$¢ $/" } 类似于一个代码块。 2 显示它捕获的内容。

  • 最后的 123 表明,在正则表达式的顶层,$/ 具有相同的值。

[4] 例如,上面脚注 3 中的代码在 { ... } 块中包含任意代码。更一般地说:

  • 规则可以递归调用;

  • 规则可以有完整的签名和传递参数;

  • 规则可以包含任意代码;

  • 规则可以使用多个分派语义进行解析。值得注意的是,这可以包括基于最长匹配长度的分辨率。

我想知道 Raku 的 trim() 例程是否适合您的目的,例如:.trim.trim-trailing 甚至 .trim-leading。在 Raku REPL 中:

> say 'x x  x   ' ~~ m:g/ 'x'+  \s* /;    
(「x 」 「x  」 「x   」)    

> say 'x x  x   '.trim-trailing ~~ m:g/ 'x'+  \s* /;    
(「x 」 「x  」 「x」)

HTH.

https://docs.raku.org/routine/trim https://docs.raku.org/routine/trim-trailing https://docs.raku.org/routine/trim-leading