Scala将字符串转换为带有条件

时间:2015-12-09 10:50:19

标签: scala

"(school A and school B) or (school C or school D)"这样的字符串。 所以字符串如下:

val queryString = "(school A and school B) or (school C or school D)" 

预期产出

val firstList = List ( "school A", "school B", "and" )
val secondList = List ( "school C", "school D" , "or")
val operatorList = List("or")

queryString也应该是and条件:

val queryString = "(school A and school B) and (school C or school D)"

预期产出

val firstList = List ( "school A", "school B", "and" )
val secondList = List ( "school C", "school D" , "or")
val operatorList = List("and")

也有一段时间queryString应该只有这样一个标准:

val queryString = "(school A and school B)" 

预期产出

val firstList = List ( "school A", "school B", "and" )
val secondList = empty list
val operatorList = empty list

firstList包含字符串第一个开括号和右括号数据(school A and school B)firstListList ( "school A", "school B", "and" ) secondList相同。

我用最后一个字符串做如下:

val queryString = "(school A and school B)"

此替换为( and ) to ""并由and

拆分
queryString.replaceAll("\\(|\\)","").split("and")

这个返回Array("school A ", " school B")但是在上面的代码中我手动分割and这个工作在(school A and school B)只有这个字符串如果字符串很大那么这个逻辑就失败了。

2 个答案:

答案 0 :(得分:4)

我建议使用解析器组合器来完成这项任务。 毫无疑问,你需要一些时间来弄清楚它是如何工作的。 但这里的基本实现适用于一半的样本。

您可以改进它以适用于所有情况。

class SParser extends RegexParsers {

  def word = "\\w+".r
  def or = "or"

  def oper = "and" | "or"
  def oneQ = "(" ~ word ~ oper  ~ word ~ ")" ^^ {
    case _ ~ s1 ~ op ~ s2 ~ _ => List(s1, s2, op)
  }

  def q1 = oneQ ~ oper ~ oneQ ^^ {
    case s1 ~ op ~ s2  =>
      println("firstList : " + s1)
      println("secondList: " + s2)
      println("operatorList: " + op)
      (s1, s2, op)
  }

  def parse(s: String) = {
    println(s"Start parse: $s")
    val res = parseAll(q1, s)
    println(res)
    res
  }

}

用法:

  val s = new SParser()
  s.parse("(SchoolA and SchoolB) or (SchoolC and SchoolD)")
  s.parse("(SchoolA and SchoolB) and (SchoolC and SchoolD)")
  // s.parse("(SchoolA and SchoolB)") // will not work for it. need implement...

输出:

Start parse: (SchoolA and SchoolB) or (SchoolC and SchoolD)
firstList : List(SchoolA, SchoolB, and)
secondList: List(SchoolC, SchoolD, and)
operatorList: or

Start parse: (SchoolA and SchoolB) and (SchoolC and SchoolD)
firstList : List(SchoolA, SchoolB, and)
secondList: List(SchoolC, SchoolD, and)
operatorList: and

<强>更新

import scala.util.parsing.combinator.RegexParsers
class SParser extends RegexParsers {

  def space = "\\s".r
  def schholName = "\\w+\\s\\w".r // regex for <school X>

  def and = "and"
  def or = "or"
  def eof = "$".r

  def oneQ(oper: String) = "(" ~ repsep(schholName, oper) ~ ")" ^^ {
    case _ ~ s1 ~ _ => s1 ++ (1 until s1.size).map( _ => oper) // add operators at the end
  }

  def allOneQ = oneQ(and) | oneQ(or)

  def q1(oper: String) = repsep(allOneQ, oper) ^^ {
    case s1  =>
      val res = s1 ++ (1 until s1.size).map(_ => oper)
      println("Lists : " + res)
      res
  }

  def fullQ = q1(and) ~ eof | q1(or) ~ eof


  def parse(s: String) = {
    println(s"Start parse: $s")
    val res = parseAll(fullQ, s)
    println(res)
    res
  }

}

用法

val s = new SParser()
s.parse("(school A or school B)")
s.parse("(school A and school B and school E)")
s.parse("(school A or school B or school E) or (school C and school D)")

结果

Start parse: (school A or school B)
Lists : List(List(school A, school B, or))
Start parse: (school A and school B and school E)
Lists : List(List(school A, school B, school E, and, and))
Start parse: (school A or school B or school E) or (school C and school D)
Lists : List(List(school A, school B, school E, or, or))
Lists : List(List(school A, school B, school E, or, or), List(school C, school D, and), or)

答案 1 :(得分:1)

我想用parboiled2

来推动V.先生的回答

结构

虽然它超出了问题范围,但让我介绍一些检查复杂条件的适当结构

trait Query {
  def check(valid: String => Boolean): Boolean
}

case class School(name: String) extends Query {
  def check(valid: (String) => Boolean) = valid(name)
}

case class And(queries: Seq[Query]) extends Query {
  def check(valid: (String) => Boolean) = queries.forall(_.check(valid))
}

case class Or(queries: Seq[Query]) extends Query {
  def check(valid: (String) => Boolean) = queries.exists(_.check(valid))
}

case object False extends Query {
  def check(valid: (String) => Boolean) = false
}

case object True extends Query {
  def check(valid: (String) => Boolean) = true
}

此处School(A)将解析等效于school A
AndOrand \ {{}}条件的合并者 orTrue是实用的常数条件。

每个False都可以运行一些查询,其中包含叶Query s

的预定义结果

分析器

让我们通过parboiled2创建解析器毛发这样的结构,这比V先生建议的标准scala解析器组合更快。

School

使用

现在您可以尝试解析并运行查询

object Query {
  class QueryParser(val input: ParserInput) extends Parser {
    def element: Rule1[Query] = rule {school | group}
    def group: Rule1[Or] = rule {"(" ~ WS ~ disjunction ~ WS ~ ")"}
    def conjunction: Rule1[And] = rule {element.+(and) ~> And.apply _}
    def disjunction: Rule1[Or] = rule {conjunction.+(or) ~> Or.apply _}

    def school = rule {"school " ~ WS ~ capture(schoolName) ~> School.apply _}
    def schoolName = rule {oneOrMore(CharPredicate.Alpha)}
    def or = rule {WS ~ "or" ~ WS}
    def and = rule {WS ~ "and" ~ WS}
    def WS = rule {zeroOrMore(anyOf(" \n\r\t\f"))}
  }

  def parse(str: String) = new QueryParser(str).disjunction.run().toOption
}