python - 在 Python 中动态评估简单的 boolean 逻辑

标签 python tree logic boolean boolean-logic

我有一些动态生成的 boolean 逻辑表达式,例如:

  • (A 或 B)和(C 或 D)
  • A 或(A 和 B)
  • 一个
  • 空 - 计算结果为 True

占位符被替换为 boolean 值。我应该,

  1. 将此信息转换为 Python 表达式,如 True or (True or False)eval 吗?
  2. 创建一棵二叉树,其中节点是 boolConjunction/Disjunction 对象并递归计算它?
  3. 将其转换为嵌套的 S 表达式并使用 Lisp 解析器?
  4. 还有别的吗?

欢迎提出建议。

最佳答案

这是我用了大约一个半小时(加上将近一个小时的重构时间)构建的一个小模块(可能有 74 行,包括空格):

str_to_token = {'True':True,
                'False':False,
                'and':lambda left, right: left and right,
                'or':lambda left, right: left or right,
                '(':'(',
                ')':')'}

empty_res = True


def create_token_lst(s, str_to_token=str_to_token):
    """create token list:
    'True or False' -> [True, lambda..., False]"""
    s = s.replace('(', ' ( ')
    s = s.replace(')', ' ) ')

    return [str_to_token[it] for it in s.split()]


def find(lst, what, start=0):
    return [i for i,it in enumerate(lst) if it == what and i >= start]


def parens(token_lst):
    """returns:
        (bool)parens_exist, left_paren_pos, right_paren_pos
    """
    left_lst = find(token_lst, '(')

    if not left_lst:
        return False, -1, -1

    left = left_lst[-1]

    #can not occur earlier, hence there are args and op.
    right = find(token_lst, ')', left + 4)[0]

    return True, left, right


def bool_eval(token_lst):
    """token_lst has length 3 and format: [left_arg, operator, right_arg]
    operator(left_arg, right_arg) is returned"""
    return token_lst[1](token_lst[0], token_lst[2])


def formatted_bool_eval(token_lst, empty_res=empty_res):
    """eval a formatted (i.e. of the form 'ToFa(ToF)') string"""
    if not token_lst:
        return empty_res

    if len(token_lst) == 1:
        return token_lst[0]

    has_parens, l_paren, r_paren = parens(token_lst)

    if not has_parens:
        return bool_eval(token_lst)

    token_lst[l_paren:r_paren + 1] = [bool_eval(token_lst[l_paren+1:r_paren])]

    return formatted_bool_eval(token_lst, bool_eval)


def nested_bool_eval(s):
    """The actual 'eval' routine,
    if 's' is empty, 'True' is returned,
    otherwise 's' is evaluated according to parentheses nesting.
    The format assumed:
        [1] 'LEFT OPERATOR RIGHT',
        where LEFT and RIGHT are either:
                True or False or '(' [1] ')' (subexpression in parentheses)
    """
    return formatted_bool_eval(create_token_lst(s))

简单的测试给出:

>>> print nested_bool_eval('')
True
>>> print nested_bool_eval('False')
False
>>> print nested_bool_eval('True or False')
True
>>> print nested_bool_eval('True and False')
False
>>> print nested_bool_eval('(True or False) and (True or False)')
True
>>> print nested_bool_eval('(True or False) and (True and False)')
False
>>> print nested_bool_eval('(True or False) or (True and False)')
True
>>> print nested_bool_eval('(True and False) or (True and False)')
False
>>> print nested_bool_eval('(True and False) or (True and (True or False))')
True

[可能部分偏离主题]

请注意,您可以轻松地配置您使用的 token (包括操作数和运算符)以及提供的穷人依赖注入(inject)方法(token_to_char=token_to_char 和 friend )在多个不同的评估器同时(只需重置“默认注入(inject)”全局变量就会让你有一个单一的行为)。

例如:

def fuzzy_bool_eval(s):
    """as normal, but:
    - an argument 'Maybe' may be :)) present
    - algebra is:
    [one of 'True', 'False', 'Maybe'] [one of 'or', 'and'] 'Maybe' -> 'Maybe'
    """
    Maybe = 'Maybe' # just an object with nice __str__

    def or_op(left, right):
        return (Maybe if Maybe in [left, right] else (left or right))

    def and_op(left, right):
        args = [left, right]

        if Maybe in args:
            if True in args:
                return Maybe # Maybe and True -> Maybe
            else:
                return False # Maybe and False -> False

        return left and right

    str_to_token = {'True':True,
                    'False':False,
                    'Maybe':Maybe,
                    'and':and_op,
                    'or':or_op,
                    '(':'(',
                    ')':')'}

    token_lst = create_token_lst(s, str_to_token=str_to_token)

    return formatted_bool_eval(token_lst)

给出:

>>> print fuzzy_bool_eval('')
True
>>> print fuzzy_bool_eval('Maybe')
Maybe
>>> print fuzzy_bool_eval('True or False')
True
>>> print fuzzy_bool_eval('True or Maybe')
Maybe
>>> print fuzzy_bool_eval('False or (False and Maybe)')
False

关于python - 在 Python 中动态评估简单的 boolean 逻辑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2467590/

相关文章:

jQuery 表单验证逻辑

python - Ipython 笔记本 : Open & Edit Files

python - 无法在 http ://www. dropzonejs.com 上使用 python selenium webdriver 上传文件

c# - C#中的解析树

algorithm - 在多棵树中找到最佳路径(多层中的多个节点)

c++ - 我的 Prim 算法 (MST) 在矩阵中的运行速度比在列表中快得多

php - 寻找两段文本之间的匹配短语?

python - 将 DataFrame 行与包含列表的几列之间的笛卡尔积相乘

python - 如何使用 PySide 将 .ui 文件加载到 python 类中?

c++ - 枚举到 char * - 在 boost 时间之前询问了这个无答案的 q‌u‌e‌s‌t‌i‌o‌n