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

时间:2017-03-01 17:46:05

标签: regex permutation perl6 negation

在正则表达式中执行的最佳方法是什么,对多个单词的否定以及构成这些单词的字符的排列是什么?

例如:我不想要

"zero dollar"
"roze dollar"
"eroz dollar"
"one dollar"
"noe dollar"
"oen dollar"

但我确实想要

"thousand dollar"
"million dollar"
"trillion dollar"

如果我写

not m/ [one | zero] \s dollar /

它不会匹配字符的排列,而外部的“not”函数会使正则表达式匹配其他所有内容,如“大爆炸”而没有正则表达式中的“美元”。

m/ <- [one] | [zero] > \s dollar/ # this is syntax error.

非常感谢!

lisprog

2 个答案:

答案 0 :(得分:6)

使用代码断言:

你可以匹配任何单词,然后使用<!{ }>断言拒绝那些排列的单词&#34; one&#34;或&#34;零&#34;:

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

使用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 $ /;

答案 1 :(得分:4)

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

在正则表达式本身里面,我使用了一个负代码断言,它传递了匹配到helper sub中的(\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;