4

フォームの文字列の解析は、Value[,Value]+を介して簡単に実行できますrep1sep(Value, ',')。値パーサーが繰り返しで以前に解析された値に依存している場合に、rep1sep機能を実現する方法はありますか?たとえば、各値が一意である必要があるという要件を適用しますか?

依存パーサーの標準的な手法はflatMapですが、それを機能させるのに問題があります。そのような試みの1つを次に示します。

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) }

Seq[A]一般的に、パーサー引数がからParser[A]:までの関数であるrep1sepの形式が必要です。

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

注:ここではユースケースに疑問があり、一意性の検証は解析後に適切に処理されることを理解しています。タブ補完の目的でSBTパーサーコンビネーターを使用しているときにこの問題が発生しました。具体的には、ユーザーがまだ入力していないキーのみのキーと値のペアの補完オプションを提示したいと思います。完全な例とビルド可能なSBTプロジェクトについては、このパーサーを参照してください。

4

2 に答える 2

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
          ^

それが私たちが望むものです。

于 2012-07-03T16:23:21.460 に答える
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 でテスト済み。

于 2015-11-18T10:45:31.733 に答える