如何基于文本表达式过滤Scala数据?求可用类库及方案
Scala 动态筛选条件解决方案
针对你需要解析文本中的条件字符串并应用到Example实例的需求,以下是几个实用的实现方案:
1. 使用 Scala-Expr 库
Scala-Expr 支持直接解析字符串表达式并在 Scala 对象上求值,完美匹配你的条件格式需求。
步骤
- 添加 SBT 依赖:
libraryDependencies += "com.github.julien-truffaut" %% "scala-expr" % "0.1.0"
- 解析条件并验证数据:
import scalaexpr.Expr // 从数据库获取的 Example 列表 val examples: List[Example] = List(Example(4.0, 60.0), Example(3.0, 70.0)) // 读取文本文件中的所有条件行 val conditions = scala.io.Source.fromFile("conditions.txt").getLines().toList // 逐个检查条件是否有匹配数据 conditions.foreach { conditionStr => val filterExpr = Expr[Example => Boolean](conditionStr) val hasMatch = examples.exists(filterExpr.eval) println(s"条件 '$conditionStr' 是否存在匹配数据: $hasMatch") }
该库支持>、<、==等比较运算符,以及and、or、not逻辑运算符,无需额外适配即可处理你的条件格式。
2. 基于 FastParse 自定义解析器
如果不想引入第三方库,可以用 FastParse 手写轻量表达式解析器,灵活性更高。
步骤
- 添加 SBT 依赖:
libraryDependencies += "com.lihaoyi" %% "fastparse" % "2.3.3"
- 实现解析逻辑:
import fastparse._, NoWhitespace._ case class Example(a: Double, b: Double) object ConditionParser { // 解析数值 private def number[_: P]: P[Double] = P(CharIn("0-9").rep(1) ~ "." ~ CharIn("0-9").rep(1)).!.map(_.toDouble) // 解析字段名 private def field[_: P]: P[String] = P(CharIn("a-z").rep(1)).! // 解析比较运算符 private def op[_: P]: P[(Double, Double) => Boolean] = P( ">" ~ Pass.map((x: Double, y: Double) => x > y) | "<" ~ Pass.map((x: Double, y: Double) => x < y) | "==" ~ Pass.map((x: Double, y: Double) => x == y) ) // 解析单个条件 private def singleCondition[_: P]: P[Example => Boolean] = P( field ~ op ~ number ).map { case (field, op, num) => example => op(field match { case "a" => example.a case "b" => example.b }, num) } // 解析逻辑组合(and/or) private def condition[_: P]: P[Example => Boolean] = P( singleCondition ~ ((" and " | " or ") ~ singleCondition).rep ).map { case (first, rest) => rest.foldLeft(first) { case (acc, (" and ", cond)) => example => acc(example) && cond(example) case (acc, (" or ", cond)) => example => acc(example) || cond(example) } } def parse(str: String): Example => Boolean = parse(str, condition(_)).get.value } // 使用示例 val examples = List(Example(4.0, 60.0), Example(3.0, 70.0)) val filterFn = ConditionParser.parse("a > 3.7 and b < 67.2") val hasMatch = examples.exists(filterFn) println(s"是否存在匹配数据: $hasMatch")
这种方式可以完全自定义支持的运算符和字段,适合你的简单业务场景,没有冗余依赖。
3. 反射动态编译(仅用于测试)
利用 Scala 反射动态编译条件字符串为函数,但存在代码注入风险,不推荐生产环境使用。
import scala.reflect.runtime.universe._ import scala.tools.reflect.ToolBox val tb = runtimeMirror(getClass.getClassLoader).mkToolBox() val example = Example(4.0, 60.0) val conditionStr = "a > 3.7 and b < 67.2" // 拼接成可编译的代码字符串 val code = s"""(example: Example) => example.$conditionStr""" val filterFn = tb.compile(tb.parse(code)).asInstanceOf[Example => Boolean] println(filterFn(example)) // 输出 true
需要额外添加scala-compiler依赖,仅适合快速验证场景。
内容的提问来源于stack exchange,提问作者ruoyu
相关产品推荐
相关产品推荐

