Skip to content

Instantly share code, notes, and snippets.

@patriziotufarolo
Last active November 4, 2016 13:12
Show Gist options
  • Save patriziotufarolo/9fc96d34ac899513690849c57c82ae5a to your computer and use it in GitHub Desktop.
Save patriziotufarolo/9fc96d34ac899513690849c57c82ae5a to your computer and use it in GitHub Desktop.
Simple evaluator for boolean expressions, supporting not, and, or, implies and iff operators. It supports nested formulas with parentheses. Based on http://stackoverflow.com/a/2472414/3800901
TOKEN = {
"True": True,
"False": False,
"and": lambda a, b: a and b,
"or": lambda a, b: a or b,
"implies": lambda a, b: (not a) or b,
"iff": lambda a, b: ((not a) or b) and ((not b) or a),
"not": lambda a: not a,
"(": "(",
")": ")"
}
class UnknownToken(Exception):
pass
class MalformedExpression(Exception):
pass
def find(input_list, obj, start=0):
return [index
for index, item in enumerate(input_list)
if item == obj and index >= start
]
def create_token_list(s):
try:
s = s.replace('(', ' ( ')
s = s.replace(')', ' ) ')
return [TOKEN[i] for i in s.split()]
except KeyError as e:
raise UnknownToken(e.args[0])
def find_inner_parentheses(input_list):
open_pars = find(input_list, '(')
if not open_pars:
return False, -1, -1
most_inner_opar = open_pars[-1]
most_inner_cpar = find(input_list, ')', most_inner_opar)[0]
return True, most_inner_opar, most_inner_cpar
def evaluate_boolean_atom(input_list):
if len(input_list) == 0:
return False
elif len(input_list) == 1:
return input_list[0]
elif len(input_list) == 2:
if not callable(input_list[0]):
raise MalformedExpression()
return input_list[0](input_list[1])
elif len(input_list) == 3:
if not callable(input_list[1]):
raise MalformedExpression()
return input_list[1](input_list[0], input_list[2])
else:
indexes_not = find(input_list, TOKEN["not"])
for index_not in indexes_not:
input_list[index_not:index_not+1] = [evaluate_boolean_atom(input_list[index_not:index_not+1])]
indexes_and = find(input_list, TOKEN["and"])
for index_and in indexes_and:
input_list[index_and-1:index_and+2] = [evaluate_boolean_atom(input_list[index_and-1:index_and+2])]
indexes_or = find(input_list, TOKEN["or"])
for index_or in indexes_or:
input_list[index_or-1:index_or+2] = [evaluate_boolean_atom(input_list[index_or-1:index_or+2])]
indexes_implies = find(input_list, TOKEN["implies"])
for index_implies in indexes_implies:
input_list[index_implies-1:index_implies+2] = [evaluate_boolean_atom(input_list[index_implies-1:index_implies+2])]
indexes_iff = find(input_list, TOKEN["iff"])
for index_iff in indexes_iff:
input_list[index_iff-1:index_iff+2] = [evaluate_boolean_atom(input_list[index_iff-1:index_iff+2])]
return evaluate_boolean_atom(input_list)
def evaluate_tokens(input_list):
if not input_list:
return False
if len(input_list) == 1:
return evaluate_boolean_atom(input_list)
has_parens, left_par, right_par = find_inner_parentheses(input_list)
if not has_parens:
return evaluate_boolean_atom(input_list)
input_list[left_par:right_par+1] = \
[evaluate_boolean_atom( input_list[left_par+1:right_par])]
return evaluate_tokens(input_list)
def evaluate(s):
return evaluate_tokens(create_token_list(s))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment