如何解析Python可求值字符串中的自定义运算符并还原表达式
需求说明
我们需要将字符串形式的公式(其中Python运算符&、|、~被替换为AND、OR、NOT,但字符串字面量内的这些词保持不变)还原为合法的Python表达式,最终目标是能直接求值该表达式。
比如输入:
str_formula = "x > 0 AND y < 5 AND 'this AND that' in my_string"
需要还原为:
python_formula = "x > 0 & y < 5 AND 'this AND that' in my_string"
要求实现需支持:
- 单双引号的字符串字面量
- 转义引号的复杂场景(如
'this AND tha\'t') - 同时处理
AND→&、OR→|、NOT→~的替换
现有实现方案
循环遍历方案(支持单双引号)
该方案通过逐字符遍历,跟踪是否处于引号内,仅替换引号外的目标运算符,已补充转义引号支持:
formula = 'x > 0 AND y < 5 AND "this AND that" in my_string' # 替换引号外的"AND"/"OR"/"NOT"为对应运算符 inverted_formula = '' in_quote = False current_quote = None i = 0 while i < len(formula): # 处理转义引号:直接复制转义符和目标字符 if formula[i] == '\\' and i + 1 < len(formula): inverted_formula += formula[i:i+2] i += 2 continue # 处理引号状态切换 if formula[i] in ('"', "'"): if not in_quote: in_quote = True current_quote = formula[i] elif formula[i] == current_quote: in_quote = False current_quote = None inverted_formula += formula[i] i += 1 continue # 替换引号外的目标运算符 if not in_quote: if formula[i:i+3] == "AND": inverted_formula += "&" i += 3 continue elif formula[i:i+2] == "OR": inverted_formula += "|" i += 2 continue elif formula[i:i+3] == "NOT": inverted_formula += "~" i += 3 continue # 复制普通字符 inverted_formula += formula[i] i += 1 print(inverted_formula)
正则方案(仅支持双引号,未处理转义)
该方案通过正向预查匹配引号外的AND,但仅支持双引号,且无法处理转义引号:
import re pattern = re.compile(r'\bAND\b(?=([^"]*"[^"]*")*[^"]*$)') inverted_formula = re.sub(pattern, '&', formula)
复杂测试用例
以下是需要支持的复杂场景测试用例:
f = "x > 0 AND y < 5 AND 'this AND tha\'t' in my_string AND 'this AND tha\'t' in my_string" f2 = 'x > 0 AND y < 5 AND "this AND tha\'t" in my_string AND "this AND tha\'t" in my_string' f3 = "'this AND tha\'t' in my_string AND 'this AND that' in my_string"
优化思路探讨
利用AST模块
通过AST解析公式字符串,精准区分运算符标识符和字符串内的词,替换后再反编译为Python代码。这种方法天然支持所有合法Python字符串格式:
import ast import astunparse class OperatorReplacer(ast.NodeTransformer): def visit_Name(self, node): if node.id == 'AND': return ast.BitAnd() elif node.id == 'OR': return ast.BitOr() elif node.id == 'NOT': return ast.Invert() return node def replace_operators(formula_str): # 解析为AST tree = ast.parse(formula_str, mode='eval') # 替换运算符节点 tree = OperatorReplacer().visit(tree) # 反编译为代码字符串 return astunparse.unparse(tree).strip() # 测试 test_formula = "x > 0 AND y < 5 AND 'this AND that' in my_string" print(replace_operators(test_formula))
注:需提前安装astunparse(pip install astunparse),且公式需符合Python表达式结构(除运算符替换外)
变量赋值技巧
通过给AND、OR、NOT赋值为对应运算符,直接执行表达式字符串。此方法无需修改公式,但存在安全风险,仅适用于可信输入:
def evaluate_formula(formula_str, context): # 定义运算符别名 AND = lambda a,b: a & b OR = lambda a,b: a | b NOT = lambda x: ~x # 合并上下文与运算符别名 exec_context = {**context, 'AND': AND, 'OR': OR, 'NOT': NOT} # 执行表达式 return eval(formula_str, exec_context) # 测试 context = {'x': 1, 'y': 3, 'my_string': 'this AND that'} result = evaluate_formula("x > 0 AND y < 5 AND 'this AND that' in my_string", context) print(result) # 输出 True
内容的提问来源于stack exchange,提问作者Ziur Olpa
相关产品推荐
相关产品推荐

