gpt4 book ai didi

Scala - 创建基本的动态函数解析器

转载 作者:行者123 更新时间:2023-12-01 19:38:39 25 4
gpt4 key购买 nike

我是 Scala 新手,但我想知道是否可以用该语言实现一个简单的方程解析器。

假设我有一些函数(很像 Excel 函数):

IF(Cond a=b, val_true, val_false)

MID(String, Start_pos, num_chars) - 字符串提取

LEN(String) - 字符串的长度

OR(cond1, cond2, ... condn)

AND(cond1, cond2, ... condn)

因此,我的想法是,我可以在运行时将公式作为来自用户的字符串作为命令行参数以及任何其他参数传入,例如 IF(LEN(param1)=4,MID(param1,2) ,1), MID(param1,0,LEN(param1)))

这个想法是评估函数,因此如果用户提供上述公式和字符串“scat”,那么输出将为“a”。如果给出字符串“scala”,那么输出将为“scala”...

这在 Scala 中实现起来有多容易?最好的设计方法是什么?我知道没有函数指针(在 C 中,我会将公式字符串解析为 func 点的集合,然后从那里消失)...

任何有关如何以高效的 Scala 风格解决此问题的建议将不胜感激。

干杯!

最佳答案

这个问题促使我们尝试 combinator parsers 。给定代表表达式子集的以下代数数据类型:

import scala.util.parsing.combinator._
object Expr { type VARS = Map[String, Any] }
import Expr._
sealed trait Expr { def eval(v: VARS) : Any }

case class If(cond: Cond, ifTrue: Expr, ifFalse: Expr) extends Expr {
def eval(v: VARS) =
if (cond.eval(v)) ifTrue.eval(v) else ifFalse.eval(v)
}
case class Cond(left: Expr, right: Expr) extends Expr {
def eval(v: VARS) = left.eval(v) == right.eval(v)
}
case class Len(ident: String) extends Expr {
def eval(v: VARS) = v(ident).toString.size
}
case class Mid(ident: String, start: Expr, count: Expr) extends Expr {
def eval(v: VARS) = {
val s = start.eval(v).asInstanceOf[Int]
val e = s + count.eval(v).asInstanceOf[Int]
v(ident).asInstanceOf[String].substring(s, e)
}
}
case class Ident(ident: String) extends Expr { def eval(v:VARS) = v(ident) }
case class StringLit(value: String) extends Expr { def eval(v:VARS) = value }
case class Number(value: String) extends Expr { def eval(v:VARS) = value.toInt }

以下解析器定义将解析给定的表达式并返回一个 Expr 对象:

class Equation extends JavaTokenParsers {
def IF: Parser[If] = "IF" ~ "(" ~ booleanExpr ~","~ expr ~","~ expr ~ ")" ^^ {
case "IF" ~ "(" ~ booleanExpr ~ "," ~ ifTrue ~ "," ~ ifFalse ~ ")" =>
If(booleanExpr, ifTrue, ifFalse)
}
def LEN: Parser[Len] = "LEN" ~> "(" ~> ident <~ ")" ^^ (Len(_))
def MID: Parser[Mid] = "MID" ~ "(" ~ ident ~ "," ~ expr ~ "," ~ expr ~ ")" ^^ {
case "MID" ~ "(" ~ ident ~ "," ~ expr1 ~ "," ~ expr2 ~ ")" =>
Mid(ident, expr1, expr2)
}
def expr: Parser[Expr] = (
stringLiteral ^^ (StringLit(_))
| wholeNumber ^^ (Number(_))
| LEN
| MID
| IF
| ident ^^ (Ident(_))
)
def booleanExpr: Parser[Cond] = expr ~ "=" ~ expr ^^ {
case expr1 ~ "=" ~ expr2 => Cond(expr1, expr2)
}
}

然后可以像这样解析和评估结果:

val equation = new Equation
val parsed = equation.parseAll(equation.expr,
"""IF(LEN(param1)=4,MID(param1,2,1), MID(param1,0,LEN(param1)))""")
parsed match {
case equation.Success(expr, _) =>
println(expr)
// If(Cond(Len(param1),Number(4)),
// Mid(param1,Number(2),Number(1)),
// Mid(param1,Number(0),Len(param1)))
println(expr.eval(Map("param1" -> "scala"))) // prints scala
println(expr.eval(Map("param1" -> "scat"))) // prints a
case _ =>
println("cannot parse")
}

请注意,我提供的语法只是使示例解析的最低语法,并且绝对没有错误管理或类型检查。在流程方面,我首先想出了一个没有产生式 ^^ ... 的语法来解析您的示例,然后添加 Expr 类型但没有 eval 方法,然后生产 ^^ ...,然后我最终将 eval 方法添加到 Expr 特征和子类中。

关于Scala - 创建基本的动态函数解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9780196/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com