Regex scala中的表达式计算器(可能带有占位符?)

Regex scala中的表达式计算器(可能带有占位符?),regex,scala,Regex,Scala,我正在从配置文件中读取类似的内容: metric1.critical = "<2000 || >20000" metric1.okay = "=1" metric1.warning = "<=3000" metric2.okay = ">0.9 && < 1.1 " metric3.warning ="( >0.9 && <1.5) || (<500 &&>200)" 我的目标是基本上评估

我正在从配置文件中读取类似的内容:

metric1.critical = "<2000 || >20000"
metric1.okay = "=1"
metric1.warning = "<=3000"
metric2.okay = ">0.9 && < 1.1 "
metric3.warning ="( >0.9 && <1.5) || (<500 &&>200)"
我的目标是基本上评估

    if(metric1.value<2000 || metric1.value > 20000)
     metric1.setAlert("critical");
    else if(metric1.value=1)
     metric.setAlert("okay");
    //and so on
if(metric1.value 20000)
metric1.setAlert(“严重”);
else if(metric1.value=1)
metric.setAlert(“正常”);
//等等
我不太擅长正则表达式,所以我会尽量不使用它。我正在用Scala编写代码,我想知道是否有任何现有的库可以提供帮助。也许我需要放置占位符来填充空格,然后计算表达式?但是,如何以更少的开销最有效地计算表达式

编辑: 在java中,我们是如何拥有表达式计算器库的,我希望能为我的代码找到类似的东西。也许我可以在配置文件中添加像“?”这样的占位符来代替metric1.value(读取变量),然后使用计算器? 或 有人能推荐一个好的正则表达式吗?
提前谢谢

这听起来像是要使用解析器组合器库定义自己的语法

scala类库中内置了一个解析器组合器。由于scala库已经模块化,它现在是一个单独的项目,位于

更新:每个寻找概念上类似于scala解析器组合器的解析器组合器库的人都应该看看。它非常快,并且不使用宏。因此,它可以作为scala解析器组合器的替代品

在第33章“组合分析”中有一些关于如何使用它的示例

这里有一个小语法、ast和evaluator让您开始学习。这缺少很多东西,例如空格处理、运算符优先级等。您也不应该使用字符串来编码不同的比较运算符。但我认为,通过这一章和Scala编程中的一章,您应该能够找到适合您需要的东西

import scala.util.parsing.combinator.{JavaTokenParsers, PackratParsers}

sealed abstract class AST
sealed abstract class BooleanExpression extends AST
case class BooleanOperation(op: String, lhs: BooleanExpression, rhs:BooleanExpression) extends BooleanExpression
case class Comparison(op:String, rhs:Constant) extends BooleanExpression
case class Constant(value: Double) extends AST

object ConditionParser extends JavaTokenParsers with PackratParsers {

  val booleanOperator : PackratParser[String] = literal("||") | literal("&&")
  val comparisonOperator : PackratParser[String] = literal("<=") | literal(">=") | literal("==") | literal("!=") | literal("<") | literal(">")
  val constant : PackratParser[Constant] = floatingPointNumber.^^ { x => Constant(x.toDouble) }
  val comparison : PackratParser[Comparison] = (comparisonOperator ~ constant) ^^ { case op ~ rhs => Comparison(op, rhs) }
  lazy val p1 : PackratParser[BooleanExpression] = booleanOperation | comparison
  val booleanOperation = (p1 ~ booleanOperator ~ p1) ^^ { case lhs ~ op ~ rhs => BooleanOperation(op, lhs, rhs) }
}

object Evaluator {

  def evaluate(expression:BooleanExpression, value:Double) : Boolean = expression match {
    case Comparison("<=", Constant(c)) => value <= c
    case Comparison(">=", Constant(c)) => value >= c
    case Comparison("==", Constant(c)) => value == c
    case Comparison("!=", Constant(c)) => value != c
    case Comparison("<", Constant(c)) => value < c
    case Comparison(">", Constant(c)) => value > c
    case BooleanOperation("||", a, b) => evaluate(a, value) || evaluate(b, value)
    case BooleanOperation("&&", a, b) => evaluate(a, value) && evaluate(b, value)
  }
}

object Test extends App {

  def parse(text:String) : BooleanExpression = ConditionParser.parseAll(ConditionParser.p1, text).get

  val texts = Seq(
    "<2000",
    "<2000||>20000",
    "==1",
    "<=3000",
    ">0.9&&<1.1")

  val xs = Seq(0.0, 1.0, 100000.0)

  for {
    text <- texts
    expression = parse(text)
    x <- xs
    result = Evaluator.evaluate(expression, x)
  } {
    println(s"$text $expression $x $result")
  }
}
import scala.util.parsing.combinator.{JavaTokenParsers,PackratParsers}
密封抽象类AST
密封抽象类BooleanExpression扩展了AST
case类BooleanOperation(op:String,lhs:BooleanExpression,rhs:BooleanExpression)扩展了BooleanExpression
case类比较(op:String,rhs:Constant)扩展了布尔表达式
案例类常量(值:双精度)扩展AST
对象ConditionParser使用packratParser扩展了JavaTokenParser{
val booleanOperator:PackratParser[String]=literal(“| |”)| literal(&&&”)
val comparisonOperator:PackratParser[String]=文字(“=”)|文字(“=”)|文字(“!=”)|文字(“”)
val常量:PackratParser[constant]=floatingPointNumber.^{x=>constant(x.toDouble)}
val比较:PackratParser[comparison]=(comparisonOperator~constant)^{case op~rhs=>comparison(op,rhs)}
lazy val p1:PackratParser[BooleanExpression]=booleanOperation |比较
val booleanOperation=(p1~booleanOperator~p1)^{case lhs~op~rhs=>booleanOperation(op,lhs,rhs)}
}
对象计算器{
def求值(表达式:布尔表达式,值:双精度):布尔=表达式匹配{
大小写比较(“=”,常数(c))=>值>=c
大小写比较(“==”,常数(c))=>value==c
大小写比较(“!=”,常数(c))=>值!=c
大小写比较(“,常数(c))=>value>c
大小写布尔运算(“||”,a,b)=>求值(a,值)|求值(b,值)
case布尔运算(“&&”,a,b)=>求值(a,value)&&evaluate(b,value)
}
}
对象测试扩展应用程序{
def parse(text:String):booleanpression=ConditionParser.parseAll(ConditionParser.p1,text).get
val文本=序号(

“Scala内置了解释器库,您可以使用它。该库提供了与许多其他语言中的
eval()
类似的功能。您可以将Scala代码片段作为字符串传递给
.exploration
方法,它将对其进行评估

import scala.tools.nsc.{ Interpreter, Settings }

val settings = new Settings   
settings.usejavacp.value = true
val in = new Interpreter(settings) 
val lowerCritical = "<2000" // set the value from config
val value = 200   
in.interpret(s"$value $lowerCritical")                    //> res0: Boolean = true
val value1 = 20000                               //> value1  : Int = 20000
in.interpret(s"$value1 $lowerCritical")          //> res1: Boolean = false
导入scala.tools.nsc.{解释器,设置}
val设置=新设置
settings.usejavacp.value=true
val in=新的解释器(设置)

val lowerCritical=“您希望为此使用实际的解析器

大多数答案都建议使用Scala的解析器组合器,如果有点过时的话,这是一个非常有效的选择

我建议使用另一种解析器组合器实现,它具有以Scala宏的形式编写的明显优势——不需要太过技术化,这意味着您的解析器是在编译时而不是运行时生成的,这可以显著提高性能。一些基准测试的Parboiled2速度是Scala的200倍解析器组合器


由于解析器组合器现在处于一个单独的依赖关系中(我相信从2.11开始),确实没有充分的理由选择它们而不是Parboiled2。

我最近遇到了同样的问题,我最终编写了自己的表达式求值库。它是一个简单的库,但它可以验证/求值与问题中的表达式类似的表达式。您可以执行以下操作:

val ctx = Map("id" -> 10L, "name" -> "sensor1")
val parser = ExpressionParser()
val expr = parser.parseBooleanExpression(""" id == 10L || name == "sensor1" """).get
println(expr3.resolve(ctx3)) // prints true

如果您不想使用该库,我建议使用解析器…它比解析器组合器快得多,比parboiled慢一点,但比两者都容易使用。

是这里的最佳解决方案。请参阅。还有,但我不推荐它。解析器组合器库不再是scala库的一部分(至少在某些情况下)。添加到您的答案中可能会很有用。问题是我没有足够的时间来编写解析器。我希望找到一个相同的库。我想您的knwoledge?:\对于标准表达式,例如(x100)您可以重用现有的语法分析器或语法。但是您想要的语法有点不标准。因此,显然没有现有的库。但是用Scala编写语法分析器非常简单,而且非常有趣,也是一种学习的好方法。最重要的工作是思考您想要的语法。这与您使用的语言/框架无关现在不推荐使用解释器
val ctx = Map("id" -> 10L, "name" -> "sensor1")
val parser = ExpressionParser()
val expr = parser.parseBooleanExpression(""" id == 10L || name == "sensor1" """).get
println(expr3.resolve(ctx3)) // prints true