2012-07-03 147 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。