Added another improvement to this converter: "word not in keywords" feature. This is becoming interesting!
This is an updated code that tries many queries with a simple expression validation included:
#!perl -w
my @data = <DATA>;
for my $test (
# (
"olive&(popeye|bluto)",
"(tom&jerry)|(sylvester&tweety)",
"moe&(shemp|curly|joe)&larry",
"moe curly larry", # "&" is optional
"moe&!curly&larry", # curly not present
"moe ( shemp | curly | joe ) larry", # "|" is required
"jerry -tom", # standard way of "AND" and "AND NOT"...
"(moe)((shemp)|(curly)|(joe))(larry)", # also this
"tom&jerry|sylvester&tweety", # use re's default precedence
"moe(&shemp|curly|joe)&larry", # error: "(&" instead of "&("
"moe ( shemp | curly | joe", # error: missing ")"
"moe ) curly ( larry", # invalid: bad grouping
"(olive)&(popeye|(bluto|brutus)))", # error: extra ")"
"(jerry)((tweety))( )", # error: empty group
"jerry||tweety", # error: empty word
"olive - (bluto | brutus)", # only words can be excluded
"olive - bluto - brutus", # Ok, spaces ignored.
"(curly|!larry)&!moe", # valid, but senseless OR
"moe&!(!curly)&larry", # error: curly present?
"tom -!jerry" # error: don't try...
# )[(shift)-1]
)
{
print "\n\n$test\n::\n";
(print("ERROR: Invalid expression\n") , next)
if $test =~ /[^a-z\s\&\|\(\)\!\-]|^\s*[\&\|]|[\&\|]\s*$|[\&\|\(]\s
+*[\&\|\)]|[\!\-]\s*[^a-z\s]/;
# not_valid_chars |op_begins | op_ends | no_consec
+utive_ops| negated_operator
my $pars = $test;
my $i = 0;
$i++ while $pars =~ s/\((.*?)\)/$1/;
(print("ERROR: Unpaired $1 of other $i pairs found\n") , next)
if $pars =~ /([\(\)])/;
my $expr = $test;
$expr =~ s/([!\-]?)\s*(\w+)/($1?"(?!":"(?=").".*\\b$2\\b)"/ge;
$expr =~ s/[\&\s]//g;
$expr = "^($expr)";
print "$expr\n::\n";
print grep /$expr/, @data;
}
__DATA__
tom,jerry
jerry,tom
jerry,tomas
sylvester,tweety
tweeter,sylvester
tom,sylvester
popeye,olive
olive,brutus
moe,larry
shemp,curly,joe
larry,moe
larry,curly,moe
To try just one of the queries, remove the comment's chars from the for at the begining, and give a number (starting from 1) as an argument in the command line.
I also removed the captures while building the regexp because them aren't used. I've just put them there for clarification.
The validation code is simple because the allowed syntax is simple too, and is very tied to regular expressions.
BTW, is there a better way to write the lines to check for parity of parentheses?
|