- Правила разделяются пробелом
< 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, как указано символом ",".
- Должны присутствовать все 3 элемента, отмеченные знаком «+».
< ul>
Все, кроме K00582 и K00583, поскольку перед ними стоят символы «-», а если присутствует «+», то должны присутствовать все элементы.
[*]Правило 4: (K00399+K00401+K00402)
- Все 3 пункта должны присутствовать, как указано Знак "+"
- Это проще, чем кажется. Либо (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