2012-07-03 87 views
4

解析表单Value[,Value]+的字符串可以通过rep1sep(Value, ',')轻松完成。当值解析器依赖于重复中先前解析的值时,是否有办法实现rep1sep功能?例如,强制要求每个值必须是唯一的?使用Scala/SBT解析器组合器重复依赖解析器

依赖分析器的标准技术是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解析组合器来实现制表符完成时,我遇到了这个问题 - 具体来说,我想仅为那些用户尚未输入的键提供键/值对的完成选项。见this parser for a full example和可建立的SBT项目。

回答

4

以下是不太一般为您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 
     ^

哪个我们想要什么。

+0

谢谢!我推广到rep1sepDep,但我留下了我目前的实现有相同的选项卡完成问题。我现在想知道在使用flatMap时这是否是SBT完成支持中的一个怪癖。 – mpilquist

+1

Scratch - 错误是由于在解析器的早期部分中过度接受生产。详情请见:https://github.com/mpilquist/cjmx/commit/6f146c8c74fd45252e1fba6b665a4f9909565f79 – mpilquist

+0

'scala.util.parsing'和SBT解析器是否兼容? –

0

这里是用于选择一些项目与辅助完成,避免重复品溶液:

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。