277 lines
9.0 KiB
Python
277 lines
9.0 KiB
Python
"""
|
||
条件表达式解析器
|
||
支持更复杂的条件判断表达式
|
||
"""
|
||
import re
|
||
import json
|
||
from typing import Dict, Any, Union
|
||
|
||
|
||
class ConditionParser:
|
||
"""条件表达式解析器"""
|
||
|
||
# 支持的运算符
|
||
OPERATORS = {
|
||
'==': lambda a, b: a == b,
|
||
'!=': lambda a, b: a != b,
|
||
'>': lambda a, b: a > b,
|
||
'>=': lambda a, b: a >= b,
|
||
'<': lambda a, b: a < b,
|
||
'<=': lambda a, b: a <= b,
|
||
'in': lambda a, b: a in b if isinstance(b, (list, str, dict)) else False,
|
||
'not in': lambda a, b: a not in b if isinstance(b, (list, str, dict)) else False,
|
||
'contains': lambda a, b: b in str(a) if a is not None else False,
|
||
'not contains': lambda a, b: b not in str(a) if a is not None else True,
|
||
}
|
||
|
||
# 逻辑运算符
|
||
LOGICAL_OPERATORS = {
|
||
'and': lambda a, b: a and b,
|
||
'or': lambda a, b: a or b,
|
||
'not': lambda a: not a,
|
||
}
|
||
|
||
@staticmethod
|
||
def get_value(path: str, data: Dict[str, Any]) -> Any:
|
||
"""
|
||
从数据中获取值(支持嵌套路径)
|
||
|
||
Args:
|
||
path: 路径,如 'user.name' 或 'items[0].price'
|
||
data: 数据字典
|
||
|
||
Returns:
|
||
值,如果不存在返回None
|
||
"""
|
||
try:
|
||
# 处理数组索引,如 items[0]
|
||
if '[' in path and ']' in path:
|
||
parts = re.split(r'\[|\]', path)
|
||
value = data
|
||
for part in parts:
|
||
if not part:
|
||
continue
|
||
if part.isdigit():
|
||
value = value[int(part)]
|
||
else:
|
||
value = value.get(part) if isinstance(value, dict) else None
|
||
if value is None:
|
||
return None
|
||
return value
|
||
|
||
# 处理嵌套路径,如 user.name
|
||
keys = path.split('.')
|
||
value = data
|
||
for key in keys:
|
||
if isinstance(value, dict):
|
||
value = value.get(key)
|
||
elif isinstance(value, list) and key.isdigit():
|
||
value = value[int(key)] if int(key) < len(value) else None
|
||
else:
|
||
return None
|
||
if value is None:
|
||
return None
|
||
return value
|
||
except (KeyError, IndexError, TypeError, AttributeError):
|
||
return None
|
||
|
||
@staticmethod
|
||
def parse_value(value_str: str) -> Any:
|
||
"""
|
||
解析值字符串(支持字符串、数字、布尔值、JSON)
|
||
|
||
Args:
|
||
value_str: 值字符串
|
||
|
||
Returns:
|
||
解析后的值
|
||
"""
|
||
value_str = value_str.strip()
|
||
|
||
# 布尔值
|
||
if value_str.lower() == 'true':
|
||
return True
|
||
if value_str.lower() == 'false':
|
||
return False
|
||
|
||
# None
|
||
if value_str.lower() == 'null' or value_str.lower() == 'none':
|
||
return None
|
||
|
||
# 数字
|
||
try:
|
||
if '.' in value_str:
|
||
return float(value_str)
|
||
return int(value_str)
|
||
except ValueError:
|
||
pass
|
||
|
||
# JSON
|
||
if value_str.startswith('{') or value_str.startswith('['):
|
||
try:
|
||
return json.loads(value_str)
|
||
except json.JSONDecodeError:
|
||
pass
|
||
|
||
# 字符串(移除引号)
|
||
if (value_str.startswith('"') and value_str.endswith('"')) or \
|
||
(value_str.startswith("'") and value_str.endswith("'")):
|
||
return value_str[1:-1]
|
||
|
||
return value_str
|
||
|
||
@staticmethod
|
||
def evaluate_simple_condition(condition: str, data: Dict[str, Any]) -> bool:
|
||
"""
|
||
评估简单条件表达式
|
||
|
||
支持的格式:
|
||
- {key} == value
|
||
- {key} > value
|
||
- {key} in [value1, value2]
|
||
- {key} contains "text"
|
||
|
||
Args:
|
||
condition: 条件表达式
|
||
data: 输入数据
|
||
|
||
Returns:
|
||
条件结果
|
||
"""
|
||
condition = condition.strip()
|
||
|
||
# 替换变量 {key}
|
||
for key, value in data.items():
|
||
placeholder = f'{{{key}}}'
|
||
if placeholder in condition:
|
||
# 如果值是复杂类型,转换为JSON字符串
|
||
if isinstance(value, (dict, list)):
|
||
condition = condition.replace(placeholder, json.dumps(value, ensure_ascii=False))
|
||
else:
|
||
condition = condition.replace(placeholder, str(value))
|
||
|
||
# 尝试解析为Python表达式(安全方式)
|
||
try:
|
||
# 只允许安全的操作
|
||
safe_dict = {
|
||
'__builtins__': {},
|
||
'True': True,
|
||
'False': False,
|
||
'None': None,
|
||
'null': None,
|
||
}
|
||
|
||
# 添加数据中的值到安全字典
|
||
for key, value in data.items():
|
||
# 只添加简单的值,避免复杂对象
|
||
if isinstance(value, (str, int, float, bool, type(None))):
|
||
safe_dict[key] = value
|
||
|
||
# 尝试评估
|
||
result = eval(condition, safe_dict)
|
||
if isinstance(result, bool):
|
||
return result
|
||
except:
|
||
pass
|
||
|
||
# 如果eval失败,尝试手动解析
|
||
# 匹配运算符
|
||
for op in ConditionParser.OPERATORS.keys():
|
||
if op in condition:
|
||
parts = condition.split(op, 1)
|
||
if len(parts) == 2:
|
||
left = parts[0].strip()
|
||
right = parts[1].strip()
|
||
|
||
# 获取左侧值
|
||
if left.startswith('{') and left.endswith('}'):
|
||
key = left[1:-1]
|
||
left_value = ConditionParser.get_value(key, data)
|
||
else:
|
||
left_value = ConditionParser.parse_value(left)
|
||
|
||
# 获取右侧值
|
||
right_value = ConditionParser.parse_value(right)
|
||
|
||
# 执行比较
|
||
if left_value is not None:
|
||
return ConditionParser.OPERATORS[op](left_value, right_value)
|
||
|
||
# 默认返回False
|
||
return False
|
||
|
||
@staticmethod
|
||
def evaluate_condition(condition: str, data: Dict[str, Any]) -> bool:
|
||
"""
|
||
评估条件表达式(支持复杂表达式)
|
||
|
||
支持的格式:
|
||
- 简单条件: {key} == value
|
||
- 逻辑组合: {key} > 10 and {key} < 20
|
||
- 括号分组: ({key} == 'a' or {key} == 'b') and {other} > 0
|
||
|
||
Args:
|
||
condition: 条件表达式
|
||
data: 输入数据
|
||
|
||
Returns:
|
||
条件结果
|
||
"""
|
||
if not condition:
|
||
return False
|
||
|
||
condition = condition.strip()
|
||
|
||
# 处理括号表达式(递归处理)
|
||
def process_parentheses(expr: str) -> str:
|
||
"""处理括号表达式"""
|
||
while '(' in expr and ')' in expr:
|
||
# 找到最内层的括号
|
||
start = expr.rfind('(')
|
||
end = expr.find(')', start)
|
||
if end == -1:
|
||
break
|
||
|
||
# 提取括号内的表达式
|
||
inner_expr = expr[start+1:end]
|
||
inner_result = ConditionParser.evaluate_condition(inner_expr, data)
|
||
|
||
# 替换括号表达式为结果
|
||
expr = expr[:start] + str(inner_result) + expr[end+1:]
|
||
return expr
|
||
|
||
condition = process_parentheses(condition)
|
||
|
||
# 分割逻辑运算符,按优先级处理
|
||
# 先处理 and(优先级更高)
|
||
if ' and ' in condition.lower():
|
||
parts = re.split(r'\s+and\s+', condition, flags=re.IGNORECASE)
|
||
results = []
|
||
for part in parts:
|
||
part = part.strip()
|
||
if part:
|
||
results.append(ConditionParser.evaluate_simple_condition(part, data))
|
||
return all(results)
|
||
|
||
# 再处理 or
|
||
if ' or ' in condition.lower():
|
||
parts = re.split(r'\s+or\s+', condition, flags=re.IGNORECASE)
|
||
results = []
|
||
for part in parts:
|
||
part = part.strip()
|
||
if part:
|
||
results.append(ConditionParser.evaluate_simple_condition(part, data))
|
||
return any(results)
|
||
|
||
# 处理 not
|
||
if condition.lower().startswith('not '):
|
||
inner = condition[4:].strip()
|
||
return not ConditionParser.evaluate_simple_condition(inner, data)
|
||
|
||
# 最终评估简单条件
|
||
return ConditionParser.evaluate_simple_condition(condition, data)
|
||
|
||
|
||
# 全局实例
|
||
condition_parser = ConditionParser()
|