You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Scala Parser Combinator支持逻辑运算及大小写不敏感并提取键?

刚好我之前用过Scala Parser Combinator做类似的表达式解析,给你一套完整的实现方案,完美匹配你的需求——提取比较表达式左边的键,支持大小写不敏感的逻辑运算(AND/OR),还能处理括号嵌套:

首先,我们基于Scala内置的RegexParsers来构建解析器,核心思路是拆解表达式结构:先识别单个比较表达式(提取键),再组合成带逻辑运算和括号的完整表达式,最后收集所有键。

直接上可运行的代码,带详细注释:

import scala.util.parsing.combinator.RegexParsers

class KeyParser extends RegexParsers {
  // 大小写不敏感的逻辑运算符:匹配AND/Or/aNd等任意大小写组合
  private val and: Parser[String] = "(?i)and".r
  private val or: Parser[String] = "(?i)or".r

  // 匹配$包裹的变量(仅做语法校验,不需要提取内容)
  private val variable: Parser[String] = "$" ~> "[a-zA-Z_][a-zA-Z0-9_]*".r <~ "$"

  // 支持的比较运算符:可根据需求扩展
  private val compOp: Parser[String] = "!=" | "=" | "<>" | ">=" | "<=" | ">" | "<"

  // 解析单个比较表达式,返回左边的键
  private val comparison: Parser[String] = ident ~ compOp ~ variable ^^ {
    case key ~ _ ~ _ => key // 只保留左边的键,忽略运算符和变量
  }

  // 原子表达式:带括号的完整表达式,或者单个比较表达式
  // 把单个比较表达式包装成List,方便后续合并所有键
  private def atomicExpr: Parser[List[String]] = 
    "(" ~> expr <~ ")" | comparison ^^ (List(_))

  // 完整逻辑表达式:多个原子表达式通过AND/OR连接
  // 合并所有原子表达式中的键,返回最终的键列表
  private def expr: Parser[List[String]] = 
    atomicExpr ~ rep( (and | or) ~ atomicExpr ) ^^ {
      case firstKeys ~ rest => firstKeys ++ rest.flatMap(_._2)
    }

  // 对外暴露的解析入口,返回Either处理成功/失败
  def parseKeys(input: String): Either[String, List[String]] = {
    parseAll(expr, input) match {
      case Success(result, _) => Right(result)
      case failure: NoSuccess => Left(s"解析失败:${failure.msg},位置:${failure.next.pos}")
    }
  }
}

// 测试用例,直接运行就能看到结果
object KeyParserDemo extends App {
  val parser = new KeyParser()

  val expr1 = "local_province != $province_name$ or city=$city_name$ or people_number<>$some_digit$"
  println(parser.parseKeys(expr1)) // 输出:Right(List(local_province, city, people_number))

  val expr2 = "(local_province=$province_name$)"
  println(parser.parseKeys(expr2)) // 输出:Right(List(local_province))

  val expr3 = "(local_province=$province_name$ or city=$city_name$) and (lib_name=$lib$ or version>=1.0)"
  println(parser.parseKeys(expr3)) // 输出:Right(List(local_province, city, lib_name))
}

关键细节说明:

  • 大小写不敏感的逻辑运算:通过正则的(?i)标志实现,不管是AND、Or还是aNd都能被正确匹配。
  • 括号嵌套支持:atomicExpr递归调用expr,完美处理多层括号的情况(比如((a=$x$ and b=$y$) or c=$z$)也能正常解析)。
  • 键收集逻辑:每个原子表达式返回自己的键列表,逻辑表达式把所有子表达式的键合并成一个大列表,确保不会遗漏任何键。
  • 扩展性:如果需要添加更多比较运算符,直接在compOp里加对应的符号即可;如果需要键大小写不敏感,只需要在comparison里把key转成小写/大写(比如key.toLowerCase)。

测试一下你的例子,完全符合预期!如果还有其他特殊需求(比如支持函数调用、更复杂的变量格式),可以再调整parser的规则。

内容的提问来源于stack exchange,提问作者xyz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:30:55