2010-03-18 33 views
14

tôi đã có một số biểu thức logic boolean được tạo tự động, như:động đánh giá đơn giản logic boolean bằng Python

  • (A hoặc B) và (C hoặc D)
  • A hoặc (A và B)
  • Một
  • trống - đánh giá là True

Các placeholders được thay thế bằng các phép toán luận. Tôi có nên,

  1. Chuyển đổi thông tin này sang biểu thức Python như True or (True or False)eval?
  2. Tạo cây nhị phân trong đó nút là đối tượng bool hoặc Conjunction/Disjunction và đánh giá đệ quy nó?
  3. Chuyển đổi nó thành các biểu thức S lồng nhau và sử dụng trình phân tích cú pháp Lisp?
  4. Cái gì khác?

Đề xuất được hoan nghênh.

Trả lời

10

Sẽ không khó để viết một bộ đánh giá có thể xử lý việc này, ví dụ sử dụng pyparsing. Bạn chỉ có một vài thao tác để xử lý (và, hoặc, và nhóm?), Vì vậy bạn sẽ có thể phân tích cú pháp và tự đánh giá nó.

Bạn không cần phải định hình rõ ràng cây nhị phân để đánh giá biểu thức.

+3

Ví dụ pyparsing này (http://pyparsing.wikispaces.com/file/view/simpleBool.py) nên gần như là một giải pháp thả xuống. – PaulMcG

+0

Tôi sẽ chấp nhận câu trả lời này vì nó không quá đáng sợ như 'eval()' và nó dễ dàng mở rộng nhất. –

8

Nếu bạn thiết lập dicts với người dân địa phương và globals bạn quan tâm thì bạn sẽ có thể an toàn vượt qua chúng cùng với biểu thức thành eval().

+0

Không cần sử dụng 'eval' tại đây; bạn chỉ cần đánh giá một ngôn ngữ rất đơn giản, không phải Python. (Ngoài ra, hạn chế những gì bạn vượt qua để 'eval' cho người dân địa phương/globals không làm cho nó an toàn nếu bạn cuối cùng muốn vượt qua nhiều ở tất cả, và chắc chắn không ngăn chặn tính toán không thể lớn.) –

+0

+1: Chỉ cần tạo một từ điển và sử dụng eval. –

17

Dưới đây là một nhỏ (có thể là, 74 dây chuyền bao gồm cả khoảng trắng) mô-đun tôi đã xây dựng trong khoảng một giờ rưỡi (cộng gần một giờ để tái cấu trúc):

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)) 

Các xét nghiệm đơn giản cho:

>>> 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 

[một phần off-topic có thể]

Lưu ý, các bạn có thể dễ dàng cấu hình các thẻ (cả toán hạng và toán tử) mà bạn sử dụng với các phương tiện tiêm phụ thuộc nghèo-mans được cung cấp (token_to_char=token_to_char và bạn bè) để có nhiều bộ đánh giá khác nhau cùng một lúc (chỉ cần đặt lại hình ảnh "được tiêm theo mặc định" với một hành vi đơn lẻ).

Ví dụ:

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) 

cho:

>>> 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 
+0

'nested_bool_eval' sẽ thất bại nếu bạn không thực sự thực hiện bất kỳ thao tác nào, tức là' nested_bool_eval ("True") '(hoặc False). –

+0

@Mike Graham Ah, quên trường hợp đó, sửa chữa, cảm ơn :) – mlvljr

+1

Điều này thật đáng kinh ngạc. (vỗ tay) –

Các vấn đề liên quan