如何在 Perl 6 中 negate/subtract 正则表达式(不仅仅是字符 类)?

How to negate/subtract regexes (not only character classes) in Perl 6?

可以创建 conjunction,使字符串匹配 2 个或更多 regex 模式。

> "banana" ~~ m:g/ . a && b . /
(「ba」)

此外,可以negate a character class:如果我只想匹配辅音,我可以取所有字母并减去元音字符class:

> "camelia" ~~ m:g/ <.alpha> && <-[aeiou]> /
(「c」 「m」 「l」)

但是如果我需要 negate/subtract 不是字符 class,而是任意长度的 regex 怎么办?像这样:

> "banana" ~~ m:g/ . **3 && NOT ban / # doesn't work
(「ana」)

TL;DR Moritz 的回答涵盖了一些重要问题。该答案侧重于根据 Eugene 的评论匹配子字符串 ("I want to find substring(s) that match regex R, but don't match regex A.")。


不想 想要匹配的正则表达式之前写一个断言,表明您不会立即坐下,然后跟随着您 想要匹配的正则表达式:

say "banana" ~~ m:g/ <!before ban> . ** 3 / # (「ana」)

before 断言称为 "zero width" 断言。这意味着如果它成功了(在这种情况下意味着它 而不是 "match" 因为我们写的是 !before 而不仅仅是 before),匹配的位置没有移动

(当然,如果这样的断言失败并且在当前匹配位置没有匹配的替代模式,则匹配引擎然后前进一个字符位置。)


您可能需要相反顺序的模式,首先是正匹配,然后是负匹配,如您在问题中所示。 (也许正匹配比负匹配快,所以颠倒他们的顺序会加快匹配。)

一种适用于相当简单模式的方法是使用否定 after 断言:

say "banana" ~~ m:g/ . ** 3 <!after ban> / # (「ana」)

但是,如果否定模式足够复杂,您可能需要使用此公式:

say "banana" ~~ m:g/ . ** 3 && <!before ban> .*? / # (「ana」)

这会插入一个 && regex conjunction operator,假定 LHS 模式成功,也会尝试 RHS 在重置匹配位置后 (这就是为什么 RHS 现在以<!before ban> 而不是 <!after ban>),并且要求 RHS 匹配相同长度的输入(这就是为什么 <!before ban> 后面跟着 .*? "padding")。

它对 "negate" 正则表达式意味着什么?

当您谈论正则表达式的计算机科学定义时,它总是需要匹配整个字符串。在这种情况下,否定很容易定义。但默认情况下,Perl 6 中的正则表达式 search,因此它们不必匹配整个字符串。这意味着您必须小心定义 "negate".

的含义

如果正则表达式 A 的否定意味着当 A 不匹配整个字符串时匹配的正则表达式,反之亦然,您确实可以使用 <!before ...>,但你需要小心锚定:/ ^ <!before A $ > .* / 是这个确切的否定。

如果通过否定正则表达式 A 你的意思是 "only match if A matches nowhere in the string",你必须使用像 / ^ [<!before A> .]* $ /.

这样的东西

如果您对否定有其他定义,请分享。