Как оценить вложенные логические/логические выражения в Python?Python

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Как оценить вложенные логические/логические выражения в Python?

Сообщение Anonymous »

Я работаю над сложным анализатором правил, который имеет следующие свойства:
  • Правила разделяются пробелом
    < li>Символ «+» обозначает оператор «И».
  • Символ «,» обозначает оператор «ИЛИ».
  • А «-». указывает на необязательный элемент
Я могу создавать простые правила, но у меня возникают проблемы с оценкой сложных правил во вложенных скобках.
Вот определение вложенного правила, которое я пытаюсь оценить:

Код: Выделить всё

definition = '((K00925 K00625),K01895) (K00193+K00197+K00194) (K00577+K00578+K00579+K00580+K00581-K00582-K00583+K00584) (K00399+K00401+K00402) (K22480+K22481+K22482,K03388+K03389+K03390,K08264+K08265,K03388+K03389+K03390+K14127+(K14126+K14128,K22516+K00125))'
  • Правило 1: ((K00925 K00625),K01895)

    Это как-то сложно. В основном это правило либо K00925, затем отдельно K00625, ИЛИ только K01895. Поскольку все это заключено в круглые скобки, это преобразуется в (K00925 и K00625) ИЛИ K01895, как указано символом ",".
[*]Правило 2: (K00193+K00197+K00194)
  • Должны присутствовать все 3 элемента, отмеченные знаком «+».
[*]Правило 3: (K00577+K00578+K00579+K00580+K00581-K00582-K00583+K00584)
< ul>
Все, кроме K00582 и K00583, поскольку перед ними стоят символы «-», а если присутствует «+», то должны присутствовать все элементы.


[*]Правило 4: (K00399+K00401+K00402)
  • Все 3 пункта должны присутствовать, как указано Знак "+"
[*]Правило 5: (K22480+K22481+K22482,K03388+K03389+K03390,K08264+K08265 ,K03388+K03389+K03390+K14127+(K14126+K14128,K22516+K00125))
  • Это проще, чем кажется. Либо (K22480+K22481+K22482), ИЛИ (K03388+K03389+K03390). Для последнего подправила это K08264+K08265,K03388+K03389+K03390+K14127+(либо K14126+K14128 ИЛИ K22516+K00125))
Вот почти правильный код:

Код: Выделить всё

import re

def rule_splitter(rule: str, split_characters: list) -> set:
"""
Split rule by characters.

Args:
rule (str): Boolean logical string.
split_characters (list): List of characters to split in rule.

Returns:
set: Unique symbols in a rule.
"""
rule_decomposed = str(rule)
if split_characters:
for character in split_characters:
character = character.strip()
rule_decomposed = rule_decomposed.replace(character, "")
unique_symbols = set(rule_decomposed.split())
return unique_symbols

def evaluate_rule(rule: str, items: set, replace={"+": " & ", ",": " | "}) -> bool:
"""
Evaluate a string of boolean logicals.

Args:
rule (str): Boolean logical string.
items (set): List of items in rule.
replace (dict, optional): Replace boolean characters.  Defaults to {"+":" & ", ",":" | "}.

Returns:
bool: Evaluated rule.
"""
# Handle optional items prefixed by '-'
rule = re.sub(r'-\w+', '', rule)

# Replace characters for standard logical formatting
if replace:
for character_before, character_after in replace.items():
rule = rule.replace(character_before, character_after)

# Split the rule into individual symbols
unique_symbols = rule_splitter(rule, replace.values())

# Create a dictionary with the presence of each symbol in the items
item_to_bool = {sym: (sym in items) for sym in unique_symbols}

# Remove redundant logical operators and fix syntax
rule = re.sub(r'(&\s*){2,}', ' & ', rule)  # Remove consecutive '&'
rule = rule.strip()  # Remove leading/trailing whitespace

# Parse and evaluate the rule
expr = eval(rule, {"__builtins__": None}, item_to_bool)

return expr

def handle_optional_items(rule: str) -> str:
"""
Handle optional items in a rule, indicated by a '-' prefix.

Args:
rule (str): Rule string with optional items.

Returns:
str: Modified rule string with optional items removed.
"""
# Remove optional items prefixed by '-'
rule = re.sub(r'-\w+', '', rule)
return rule

def find_rules(definition: str) -> list:
"""
Find and extract rules from the definition string.

Args:
definition (str): Complex boolean logical string with multiple rules.

Returns:
list: List of extracted rules as strings.
"""
rules = []
stack = []
current_rule = ""

for char in definition:
if char == '(':
if stack:
current_rule += char
stack.append(char)
elif char == ')':
stack.pop()
if stack:
current_rule += char
else:
rules.append(current_rule.strip())
current_rule = ""
else:
if stack:
current_rule += char

return rules

def evaluate_definition(definition: str, items: set) ->  dict:
"""
Evaluate a complex definition string involving multiple rules.

Args:
definition (str): Complex boolean logical string with multiple rules.
items (set): Set of items to check against the rules.

Returns:
dict: Dictionary with each rule and its evaluated result.
"""
# Extract individual rules from the definition
rules = re.findall(r'\([^\)]+\)', definition)

# Evaluate each rule
rule_results = {}
for rule in rules:
cleaned_rule = rule[1:-1]  # Remove the outer parentheses
try:
result = evaluate_rule(cleaned_rule, items)
except SyntaxError as e:
# Handle syntax errors from eval() due to incorrect formatting
result = False
rule_results[rule] = result

return rule_results

# Define the rules
definition = '((K00925 K00625),K01895) (K00193+K00197+K00194) (K00577+K00578+K00579+K00580+K00581-K00582-K00583+K00584) (K00399+K00401+K00402) (K22480+K22481+K22482,K03388+K03389+K03390,K08264+K08265,K03388+K03389+K03390+K14127+(K14126+K14128,K22516+K00125))'

# List of items to check against
items = {
'K00925',
# 'K00625',
# 'K01895',
'K00193',
'K00197',
'K00194',
'K00577',
'K00578',
'K00579',
'K00580',
'K00581',
'K00582',
'K00584',
'K00399',
'K00401',
'K00402',
'K22480',
'K22481',
'K22482',
'K03388',
'K03389',
'K03390',
'K08264',
'K08265',
'K14127',
'K14126',
# 'K14128',
'K22516',
# 'K00125'
}

# Evaluate the definition
result = evaluate_definition(definition, items)
result

{'((K00925 K00625)': False,
'(K00193+K00197+K00194)': True,
'(K00577+K00578+K00579+K00580+K00581-K00582-K00583+K00584)': True,
'(K00399+K00401+K00402)': True,
'(K22480+K22481+K22482,K03388+K03389+K03390,K08264+K08265,K03388+K03389+K03390+K14127+(K14126+K14128,K22516+K00125)': False}
Обратите внимание, что реализация разделяет первое правило.
Я ожидаю следующий результат:

Код: Выделить всё

{
'(K00925 K00625),K01895)':False,
'(K00193+K00197+K00194)':True,
'(K00577+K00578+K00579+K00580+K00581-K00582-K00583+K00584)':True,
'(K00399+K00401+K00402)':True,
'(K22480+K22481+K22482,K03388+K03389+K03390,K08264+K08265,K03388+K03389+K03390+K14127+(K14126+K14128,K22516+K00125)':False,
}

Вот графическое представление информационного потока для этого сложного определения правила:
Изображение


Подробнее здесь: https://stackoverflow.com/questions/788 ... -in-python
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Оценить математические выражения, которые имеют процент
    Anonymous » » в форуме JAVA
    0 Ответы
    23 Просмотры
    Последнее сообщение Anonymous
  • Как десериализовать вложенные модели Pydantic из JSON, где вложенные модели хранятся в списке в вычисляемом поле.
    Anonymous » » в форуме Python
    0 Ответы
    115 Просмотры
    Последнее сообщение Anonymous
  • Как преобразовать вложенные объекты в вложенные DTO с использованием ModelMapper?
    Anonymous » » в форуме JAVA
    0 Ответы
    93 Просмотры
    Последнее сообщение Anonymous
  • Как преобразовать вложенные объекты в вложенные DTO с использованием ModelMapper?
    Anonymous » » в форуме JAVA
    0 Ответы
    48 Просмотры
    Последнее сообщение Anonymous
  • Как печатать вложенные вложенные словаря?
    Anonymous » » в форуме Python
    0 Ответы
    4 Просмотры
    Последнее сообщение Anonymous

Вернуться в «Python»