Here's a solution that works well. It uses a helper-sub is-bad-word
that compares the $needle
(i.e. what it found in the target string) against the @badwords
and if any
matches, it'll return True.
Inside the regex itself, I've used a negative code-assertion that passes the (\w+)
that was matched into the helper sub.
One important thing to point out: If you don't properly anchor the (\w+)
to the beginning of a word (i chose beginning of the string this time) it will just skip ahead one character when it found a bad word and accept anyway (unless the bad word was only one character to begin with, like in a dollar
). After all, zero is in your @badwords
, but ero
isn't.
Hope that helps!
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;