尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
booleandev
booleandev从零到一打造一个布尔表达式解析引擎为什么需要 booleandev在复杂业务系统中我们经常遇到需要动态组合条件进行筛选的场景。比如电商平台的商品筛选器价格100 AND (品牌Apple OR 品牌Samsung)、权限系统的策略匹配、或数据清洗时的规则引擎。硬编码这些逻辑会让代码膨胀且难以维护而booleandev就是一个专注于布尔表达式解析与求值的轻量级库它能将字符串表达式转化为可执行的逻辑树并支持自定义操作符和变量上下文。在本文中我将从实战角度出发手把手带你构建一个简化版的booleandev核心并演示如何集成到真实项目中。### 核心架构Token 化 - 语法树 - 求值一个标准的布尔表达式引擎分为三个步骤1.词法分析Tokenize将字符串拆解为有意义的符号如操作数、操作符、括号。2.语法分析Parse根据运算符优先级构建抽象语法树AST。3.求值Evaluate遍历 AST结合上下文变量计算最终布尔结果。下面我们用 Python 实现一个最小可用的booleandev原型包含AND、OR、NOT、比较运算,,以及括号。#### 第一步词法分析器pythonimport refrom typing import List, Tuple# 定义 Token 类型TOKEN_PATTERN re.compile(r (?PSPACE\s) |(?POPAND|OR|NOT) |(?PCOMPARE|||!||) |(?PLPAREN\() |(?PRPAREN\)) |(?PSTRING[^]*|[^]*) |(?PNUMBER\d\.?\d*) |(?PIDENT[a-zA-Z_][a-zA-Z0-9_]*), re.VERBOSE)def tokenize(expr: str) - List[Tuple[str, str]]: 将表达式字符串转换为 (类型, 值) 的列表 tokens [] pos 0 while pos len(expr): match TOKEN_PATTERN.match(expr, pos) if not match: raise SyntaxError(f无法解析字符位置 {pos}: {expr[pos]}) pos match.end() kind match.lastgroup value match.group() if kind SPACE: continue elif kind STRING: # 去掉引号保留原始字符串值 tokens.append((STRING, value[1:-1])) elif kind NUMBER: tokens.append((NUMBER, float(value) if . in value else int(value))) else: tokens.append((kind, value)) return tokens# 测试print(tokenize(price 100 AND (brand Apple OR brand Samsung)))输出[(IDENT, price), (COMPARE, ), (NUMBER, 100), (OP, AND), (LPAREN, (), (IDENT, brand), (COMPARE, ), (STRING, Apple), (OP, OR), (IDENT, brand), (COMPARE, ), (STRING, Samsung), (RPAREN, ))]#### 第二步递归下降解析器构建 AST我们使用递归下降法定义优先级NOT 比较运算 ANDOR 括号。pythonclass ASTNode: passclass BinaryOp(ASTNode): def __init__(self, op, left, right): self.op op self.left left self.right rightclass UnaryOp(ASTNode): def __init__(self, op, operand): self.op op self.operand operandclass CompareOp(ASTNode): def __init__(self, op, left, right): self.op op self.left left self.right rightclass Identifier(ASTNode): def __init__(self, name): self.name nameclass Constant(ASTNode): def __init__(self, value): self.value valueclass Parser: def __init__(self, tokens): self.tokens tokens self.pos 0 def peek(self): return self.tokens[self.pos] if self.pos len(self.tokens) else None def consume(self, kindNone): token self.peek() if not token: raise SyntaxError(表达式意外结束) if kind and token[0] ! kind: raise SyntaxError(f期望 {kind}得到 {token}) self.pos 1 return token def parse(self): ast self.parse_or() if self.peek() is not None: raise SyntaxError(存在无法解析的剩余 token) return ast def parse_or(self): node self.parse_and() while self.peek() and self.peek()[0] OP and self.peek()[1] OR: self.consume() right self.parse_and() node BinaryOp(OR, node, right) return node def parse_and(self): node self.parse_not() while self.peek() and self.peek()[0] OP and self.peek()[1] AND: self.consume() right self.parse_not() node BinaryOp(AND, node, right) return node def parse_not(self): if self.peek() and self.peek()[0] OP and self.peek()[1] NOT: self.consume() operand self.parse_not() return UnaryOp(NOT, operand) return self.parse_compare() def parse_compare(self): left self.parse_primary() if self.peek() and self.peek()[0] COMPARE: op self.consume()[1] right self.parse_primary() return CompareOp(op, left, right) return left def parse_primary(self): token self.consume() if token[0] LPAREN: node self.parse_or() self.consume(RPAREN) return node elif token[0] IDENT: return Identifier(token[1]) elif token[0] in (NUMBER, STRING): return Constant(token[1]) else: raise SyntaxError(f意外的 token: {token})#### 第三步求值器支持变量上下文求值器需要接收一个context字典包含变量名到实际值的映射。pythondef evaluate(node, context): 递归求值 AST 节点返回布尔值 if isinstance(node, Identifier): if node.name not in context: raise KeyError(f变量 {node.name} 未在上下文中定义) return context[node.name] elif isinstance(node, Constant): return node.value elif isinstance(node, UnaryOp): val evaluate(node.operand, context) if node.op NOT: return not val elif isinstance(node, BinaryOp): left evaluate(node.left, context) right evaluate(node.right, context) if node.op AND: return left and right elif node.op OR: return left or right elif isinstance(node, CompareOp): left evaluate(node.left, context) right evaluate(node.right, context) if node.op : return left right elif node.op : return left right elif node.op : return left right elif node.op !: return left ! right elif node.op : return left right elif node.op : return left right raise ValueError(f未知节点类型: {type(node)})# 整合为一个 APIdef booleandev(expr, context): tokens tokenize(expr) parser Parser(tokens) ast parser.parse() return evaluate(ast, context)### 实战演练商品筛选器我们来测试一个真实场景筛选出价格大于 100 且品牌为 Apple 或 Samsung 的产品同时要求库存大于 0。python# 定义商品数据products [ {name: iPhone 15, price: 1299, brand: Apple, stock: 10}, {name: Galaxy S24, price: 999, brand: Samsung, stock: 0}, {name: Pixel 8, price: 899, brand: Google, stock: 5}, {name: MacBook Pro, price: 1999, brand: Apple, stock: 3},]# 构建筛选表达式expr price 100 AND (brand Apple OR brand Samsung) AND stock 0# 筛选符合条件的商品result [p for p in products if booleandev(expr, p)]print(符合条件的商品)for r in result: print(f - {r[name]} (${r[price]}, 库存 {r[stock]}))输出符合条件的商品 - iPhone 15 ($1299, 库存 10) - MacBook Pro ($1999, 库存 3)注意Galaxy S24虽然品牌符合但库存为 0被正确排除。### 扩展支持自定义函数与错误处理生产环境中的booleandev通常支持函数调用如contains(brand, App)。我们可以在求值器中加入函数分派pythonimport mathFUNCTIONS { contains: lambda s, sub: sub in s, lower: lambda s: s.lower(), abs: abs,}def evaluate_with_functions(node, context): # 在 Identifier 分支中如果上下文值是可调用对象则视为函数 if isinstance(node, Identifier) and node.name in FUNCTIONS: # 假设函数参数是后续的节点这里简化为需要额外解析实际中需扩展语法 pass # 完整实现需要调整语法分析器此处略但为了保持文章简洁我们只展示核心机制。实际库中会通过注册机制扩展。### 性能优化与注意事项1.缓存 AST如果同一表达式多次求值如每行数据应只解析一次缓存 AST 对象。2.短路求值上述代码已天然支持AND和OR的短路因为left and right在left为 False 时不会求值right避免无效计算。3.安全性在不可信表达式中应限制可访问的变量名和函数防止注入攻击。### 总结通过本文我们从零构建了一个支持AND、OR、NOT、比较和括号的布尔表达式引擎booleandev原型。核心在于将字符串解析为 AST再通过递归求值得到结果。这个模式广泛应用于规则引擎、权限校验、数据过滤等场景。实际工程中你可以扩展 Token 类型如日期、正则、支持自定义函数并加入缓存机制提升性能。希望这篇文章能激发你构建自己的表达式引擎的兴趣也欢迎在复杂场景下考虑使用成熟的库如pyparsing或lark。
RELATED

相关推荐

C++引用与临时对象:深入理解生命周期延长与性能优化

C++引用与临时对象:深入理解生命周期延长与性能优化

1. 项目概述:为什么我们还要深挖C引用?干了这么多年C,引用(Reference)这个语法糖,大家肯定都用得滚瓜烂熟了。不就是给变量起个别名嘛,初始化后不能改绑,用起来像指针但更安全。这几…

📅 2026/8/22 15:37:25
电感核心公式解析:从V=L*(di/dt)到工程选型实战

电感核心公式解析:从V=L*(di/dt)到工程选型实战

1. 从“电感”到“电感公式”:一个被误解的起点在电子工程和电路设计的日常工作中,“电感”这个词几乎每天都会出现。无论是调试一个开关电源,还是分析一个射频电路的稳定性,我们总离不开它。然而,我发现一个有趣的现象…

📅 2026/8/22 15:37:25
fastjson 1245-jdk8u342 yakit测试

fastjson 1245-jdk8u342 yakit测试

JDK8u191以后的JNDI就没那么轮椅了,得吃点操作 这周挺忙的,也是闲下来了打一打靶场 0x00 信息收集 重复操作就不一一列举了,看我往期文章。检查不在黑名单的类,858个 探测fastjson版本,1.2.45 探测能否出网&#x…

📅 2026/9/18 19:30:31
MORE NEWS

更多资讯

📰

Voyager 資料夾管理指南:為 Gemini 與 AI Studio 的 AI 對話打造真正的「檔案系統」

AI 应用前端 【免费下载链接】voyager Enhancement suite for Gemini, AI Studio, Claude & ChatGPT — plus a prompt manager for any websites, DeepSeek Harness included. / 面向 Gemini、AI Studio、Claude 与 ChatGPT 的增强套件;其中的提示词管理器可用…

📰

gatsby-source-graphql 插件全解析:将任意第三方 GraphQL API 缝合进 Gatsby 数据层

前端静态站点Web框架 【免费下载链接】gatsby React-based framework with performance, scalability, and security built in. 项目地址: https://gitcode.com/gh_mirrors/ga/gatsby 点击查看 免费下载 本篇技术指南以 gatsby-source-graphql 插件的 CHANGELOG 版…

📰

Lightweight Charts v3 到 v4 迁移指南:破坏性变更逐项分析与实战改造方案

Lightweight Charts v3 到 v4 迁移指南:破坏性变更逐项分析与实战改造方案 【免费下载链接】lightweight-charts Performant financial charts built with HTML5 canvas 项目地址: https://gitcode.com/gh_mirrors/li/lightweight-charts 本指南以 Lightweig…

📰

FoundationDB 存储基准测试上 RAM Disk:mako_storage_bench.sh 在 okteto 开发 Pod 上的 tmpfs 实践指南

分布式数据库KV存储数据库后端 【免费下载链接】foundationdb FoundationDB - the open source, distributed, transactional key-value store 项目地址: https://gitcode.com/gh_mirrors/fo/foundationdb 点击查看 免费下载 mako_storage_bench.sh 是 FoundationD…

📰

Trigger.dev SDK 公共包修改规范:Changesets 发布流程、版本策略与 @trigger.dev/core 子路径导入指南

AI Agent后端任务调度开发工具可观测性AI 应用 【免费下载链接】trigger.dev Trigger.dev – build and deploy durable AI agents and workflows 项目地址: https://gitcode.com/gh_mirrors/tr/trigger.dev 点击查看 免费下载 本篇指南围绕仓库内的 .claude/rules…

📰

swagger-codegen 生成的 Android Volley 客户端中 Pet 模型完整解析

开发工具代码生成API设计 【免费下载链接】swagger-codegen swagger-codegen contains a template-driven engine to generate documentation, API clients and server stubs in different languages by parsing your OpenAPI / Swagger definition. 项目地址: http…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬