通过Value[,Value]+
可以轻松解析rep1sep(Value, ',')
形式的字符串。当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解析组合器来完成选项卡时遇到了这个问题 - 具体来说,我想仅为那些用户尚未输入的键提供键/值对的完成选项。请参阅this parser for a full example和可构建的SBT项目。
答案 0 :(得分: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
^
这就是我们想要的。
答案 1 :(得分: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测试。