在正则表达式中执行的最佳方法是什么,对多个单词的否定以及构成这些单词的字符的排列是什么?
例如:我不想要
"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
答案 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;