使用Scala/SBT解析器组合器重复依赖解析器

使用Scala/SBT解析器组合器重复依赖解析器,scala,sbt,Scala,Sbt,解析形式为Value[,Value]+的字符串可以通过rep1sep(Value,,')轻松完成。当值解析器依赖于重复中先前解析的值时,是否有方法实现rep1sep功能?例如,强制要求每个值必须是唯一的 依赖解析器的标准技术是flatMap,但我很难让它正常工作。这里有一个这样的尝试: def Values(soFar: Set[Value]): Parser[Set[Value]] = Value(soFar) flatMap { v => (',' ~> Values(soF

解析形式为
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形式,其中parser参数是从
Seq[a]
parser[a]
的函数:

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

注意:我意识到用例在这里是有问题的,验证唯一性在解析后处理得更好。我在使用SBT解析组合符来完成制表符时遇到了这个问题——具体地说,我只想为用户尚未输入的那些键提供键/值对的完成选项。请参阅和可构建的SBT项目。

以下内容不像您的
rep1sependent
那样通用,但它可以工作:

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
          ^

这就是我们想要的。

这里有一个解决方案,用于选择一些辅助完成的项目,避免重复的项目:

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测试。

谢谢!我推广到rep1sepDep,但我仍然面临着与当前实现相同的选项卡完成问题。我现在想知道,在使用flatMap时,这是否是SBT完成支持中的一个怪癖。详细信息:scala.util.parsing和SBT解析器兼容吗?我回答自己:不,它们相似但不完全相同
scala.util.parsing
不支持自动完成。@david.perez它只是
flatMap
(和)的别名。