如何在Perl 6中取消/减去正则表达式(不仅是字符类)?

Eug*_*sky 5 perl6

可以做一个join,使字符串匹配两个或多个regex模式。

> "banana" ~~ m:g/ . a && b . /
(?ba?)
Run Code Online (Sandbox Code Playgroud)

另外,可以否定一个字符类别:如果我只想匹配辅音,我可以采用所有字母并减去元音的字符类别:

> "camelia" ~~ m:g/ <.alpha> && <-[aeiou]> /
(?c? ?m? ?l?)
Run Code Online (Sandbox Code Playgroud)

但是,如果我需要否定/减去某个字符regex长度,而不是一个字符类别,该怎么办?像这样:

> "banana" ~~ m:g/ . **3 && NOT ban / # doesn't work
(?ana?)
Run Code Online (Sandbox Code Playgroud)

rai*_*iph 5

TL; DR Moritz的答案涵盖了一些重要问题。该答案集中于根据Eugene的注释匹配子字符串(“我想找到与regex匹配R但与regex不匹配的子字符串A”。)。


写,说你是不是坐在马上断言之前,正则表达式,你希望匹配,然后按照与正则表达式,你想匹配:

say "banana" ~~ m:g/ <!before ban> . ** 3 / # (?ana?)
Run Code Online (Sandbox Code Playgroud)

before断言称为“零宽度”断言。这意味着,如果它成功(在这种情况下,意味着它不能 “投其所好”,因为我们已经写了!before,而不是仅仅before),则匹配位置不会移动。

(当然,如果这样的断言失败,并且在当前的匹配位置没有匹配的替代模式,那么匹配引擎会向前移动一个字符位置。)


正如您在问题中所显示的,您可能希望模式相反,先是正匹配,然后是负匹配。(也许正匹配比负匹配快,所以颠倒顺序将加快匹配速度。)

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

say "banana" ~~ m:g/ . ** 3 <!after ban> / # (?ana?)
Run Code Online (Sandbox Code Playgroud)

但是,如果负模式足够复杂,则可能需要使用以下公式:

say "banana" ~~ m:g/ . ** 3 && <!before ban> .*? / # (?ana?)
Run Code Online (Sandbox Code Playgroud)

这将插入一个&&正则表达式联合运算符,假定LHS模式成功,则在重置匹配位置后也会尝试RHS (这就是RHS现在以<!before ban>而不是开始的原因<!after ban>),并要求RHS匹配相同长度的输入(即为什么在<!before ban>后面加上.*?“填充”)。


mor*_*itz 4

“否定”正则表达式是什么意思?

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

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

如果通过否定正则表达式A您的意思是“仅A在字符串中没有匹配的情况下匹配”,则必须使用类似/ ^ [<!before A> .]* $ /.

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