重复依赖性解析器使用Scala / SBT解析器组合(Repeating dependent par

2019-09-19 01:00发布

解析形式的字符串Value[,Value]+可容易地通过完成rep1sep(Value, ',') 有没有办法实现rep1sep功能,当值解析器依赖于重复先前分析的价值? 例如,强制要求每个值必须是唯一的?

对于依赖解析器的标准技术是flatMap,但我有麻烦了该工作。 这里有一个这样的尝试:

def Values(soFar: Set[Value]): Parser[Set[Value]] =
  Value(soFar) flatMap { v => (',' ~> Values(soFar + v)).?.map { _ getOrElse soFar } }

def Value(soFar: Set[Value]): Parser[Value] =
  Num+ flatMap { v => if (soFar.contains(v)) failure("%d already appears".format(v)) else success(v) }

一般地,我需要rep1sep的形式,其中解析器参数是从一个函数Seq[A]Parser[A]

def rep1sepDependent(rep: Seq[A] => Parser[A], sep: Parser[Any]): Seq[A] = ???

注:我知道用例是有问题在这里和验证独特性更好地处理后的解析。 具体而言,我想提出的键/值对完成选项只有那些用户尚未输入键 - 我已经在使用SBT解析组合子的标签完成的目的,遇到了这个问题。 见这个解析器一个完整的例子和可建SBT项目。

Answer 1:

以下是不太你作为通用rep1sepDependent ,但它的工作原理:

def rep1sepUnique[T](p: => Parser[T], q: => Parser[Any]) = {
  def checkIfSeen(seen: Set[T]): Parser[Set[T]] = q ~> p >> (v =>
    if (seen(v)) failure("Duplicate: %s".format(v)) else checkIfSeen(seen + v)
  ) | success(seen)
  p >> (v => checkIfSeen(Set(v)))
}

例如:

import scala.util.parsing.combinator._

object parseUniqueWords extends RegexParsers {
  def rep1sepUnique[T](p: => Parser[T], q: => Parser[Any]) = {
    def checkIfSeen(seen: Set[T]): Parser[Set[T]] = q ~> p >> (v =>
      if (seen(v)) failure("Duplicate: %s".format(v)) else checkIfSeen(seen + v)
    ) | success(seen)
    p >> (v => checkIfSeen(Set(v)))
  }

  def apply(s: String) = parseAll(rep1sepUnique("\\w+".r, ","), s)
}

这给了我们:

scala> parseUniqueWords("aaa,bb,c")
res0: parseUniqueWords.ParseResult[Set[String]] = [1.9] parsed: Set(aaa, bb, c)

scala> parseUniqueWords("aaa,bb,aaa")
res1: parseUniqueWords.ParseResult[Set[String]] = 
[1.11] failure: Duplicate: aaa

aaa,bb,aaa
          ^

这就是我们想要的。



Answer 2:

下面是选择一些项目以辅助完成,避免重复项目的解决方案:

def select1(items: Iterable[String], separator: Parser[_] = Space) =
  token(separator ~> StringBasic.examples(FixedSetExamples(items)))

def selectSome(items: Seq[String], separator: Parser[_] = Space): Parser[Seq[String]] = {
   select1(items, separator).flatMap { v ⇒
   val remaining = items filter { _ != v }
   if (remaining.size == 0)
     success(v :: Nil)
   else
     selectSome(remaining).?.map(v +: _.getOrElse(Seq()))
 }

}

使用示例:

val myTask = inputTask[Unit]("Print selected numbers")
myTask := {
  val numbers = selectSome(Seq("One", "Two", "Three", "Four")).parsed
  numbers.foreach{ println _ }
}

测试了SBT 0.13.9。



文章来源: Repeating dependent parsers with Scala/SBT parser combinators
标签: scala sbt