解析形式的字符串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项目。
以下是不太你作为通用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
^
这就是我们想要的。
下面是选择一些项目以辅助完成,避免重复项目的解决方案:
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。