perl6在正则表达式中否定其字符的多个单词和排列

lis*_*tor 4 regex permutation negation perl6

什么是最好的表现方式,在正则表达式中,否定多个单词和构成这些单词的字符的排列?

例如:我不想要

"zero dollar"
"roze dollar"
"eroz dollar"
"one dollar"
"noe dollar"
"oen dollar"
Run Code Online (Sandbox Code Playgroud)

但我确实想要

"thousand dollar"
"million dollar"
"trillion dollar"
Run Code Online (Sandbox Code Playgroud)

如果我写

not m/ [one | zero] \s dollar /
Run Code Online (Sandbox Code Playgroud)

它不会匹配字符的排列,而外部的"非"功能会使正则表达式与正则表达式中没有"美元"的"大爆炸"相匹配.

m/ <- [one] | [zero] > \s dollar/ # this is syntax error.
Run Code Online (Sandbox Code Playgroud)

非常感谢你 !

lisprog

sml*_*mls 6

使用代码断言:

您可以匹配任何单词,然后使用<!{ }>断言来拒绝"一"或"零"排列的单词:

say "two dollar" ~~ / :s ^ (\w+) <!{ $0.comb.sort.join eq "eno" | "eorz" }> dollar $ /;
Run Code Online (Sandbox Code Playgroud)

使用before/ after:

或者,您可以预先生成不允许的单词的所有排列,然后使用正则表达式中的<!before ><!after >断言来拒绝它们:

my @disallowed = <one zero>.map(|*.comb.permutations)».join.unique;

say "two dollar" ~~ / :s ^ <!before @disallowed>\w+ dollar $ /;
say "two dollar" ~~ / :s ^ \w+<!after @disallowed> dollar $ /;
Run Code Online (Sandbox Code Playgroud)


tim*_*imo 5

这是一个运行良好的解决方案。它使用一个 helper-subis-bad-word$needle(即它在目标字符串中找到的)与 the 进行比较@badwords,如果any匹配,它将返回 True。

在正则表达式本身内部,我使用了一个否定的代码断言,(\w+)它将匹配的传递到辅助子程序中。

需要指出的一件重要事情:如果您没有正确地将 锚定(\w+)到单词的开头(这次我选择了字符串的开头),它只会在发现坏词时跳过一个字符并接受(除非坏词开头只有一个字符,例如a dollar)。毕竟,零在您的 中@badwords,但ero不是。

希望有帮助!

my @badwords = <one zero yellow>;

my @parsefails = q:to/EOF/.lines;
    zero dollar
    roze dollar
    erzo dollar
    one dollar
    noe dollar
    oen dollar
    yellow dollar
    wolley dollar
    EOF

my @parsepasses = q:to/EOF/.lines;
    thousand dollar
    million dollar
    dog dollar
    top dollar
    meme dollar
    EOF

sub is-bad-word($needle) {
    return $needle.comb.sort eq any(@badwords).comb.sort
}

use Test;
plan @parsefails + @parsepasses;

for flat (@parsefails X False), (@parsepasses X True) -> $line, $should-pass {
    my $succ = so $line ~~ / ^ (\w+) \s <!{ is-bad-word($0.Str) }> 'dollar' /;
    ok $succ eqv $should-pass, "$line -> $should-pass";
}

done-testing;
Run Code Online (Sandbox Code Playgroud)