2009-11-23 4 views
7

私は様々な "コマンド"文字列を取り込むアプリケーションを書いています。私はコマンドをトークン化するためにScalaコンビネータライブラリを見てきました。多くの場合、私はこう言っています。「これらのトークンは順序なしセットであるため、順序どおりに表示でき、表示されない可能性があります」。私は、このような(擬似文法)として配列の全ての組み合わせを定義しなければならない文法の私の現在の知識ではグラマース、スカラの構文解析のコンビネータとオーダーレスセット

command = action~content 
action = alphanum 
content = (tokenA~tokenB~tokenC | tokenB~tokenC~tokenA | tokenC~tokenB~tokenA .......) 

だから私の質問は、tokenA-Cがユニークである検討している、短い方法があります文法を使って任意の順序の集合を定義する?

答えて

3

周囲には方法があります。例えば、パーサhereを見てください。 4つの事前定義された番号を受け取ります。これは他の番号にも表示されますが、一度しか表示されていない必要があります。

def comb3[A](a: Parser[A], b: Parser[A], c: Parser[A]) = 
    a ~ b ~ c | a ~ c ~ b | b ~ a ~ c | b ~ c ~ a | c ~ a ~ b | c ~ b ~ a 
0

このような状況に頻繁に遭遇する場合は、もちろんこれを行う組み合わせルールを書くことができます。一方

は、多分オプションは「tokenA..C」だけ「トークン」を作ると、その後のハンドラ内で区別するために存在している、私はあなたが欲しいの構築物の種類を知りません

+0

この場合、各トークンはjsonスタイルのオブジェクトプロパティです。したがって、コマンドは "todo message:データベースへのTodoクラスのリンク" due:next tuesdayのように見えるかもしれないので、scalaスタイルで定義されたジェネリックルールは "token = alphanum〜 ':'〜repsep(alphanum、 '')のようなものです。しかし、私は特定のプロパティを別々に扱う必要があります。 –

+0

あなたは、同じものが2回以上出現しないことを確認しなければなりませんか? – ziggystar

+0

それは計画ですが、一部のプロパティはオプションであり、一度だけ発生する必要があります。 –

0

「トークン」サポートするには、より具体的な文法を指定する必要があります。

TODOメッセージ:別の答えにあなたのコメントからデータベースへのリンク藤堂クラス

私はあなたが

TODOメッセージのようなものを受け入れるようにしたくないと思います。データベース藤堂へのリンククラス

"link"や "to"のようなメッセージレベルのキーワードを定義したいと思うかもしれません...

def token = alphanum~':'~ "link" ~ alphanum ~ "class" ~ "to" ~ alphanum 
    ^^ { (a:String,b:String,c:String) => /* a == "message", b="Todo", c="database" */ } 

私はそのレベルで文法を定義する必要があると思います。

1

私は文法的にこの要件を強制しようとしないでしょう。

OTOH、あなたはこのパターンが頻繁に起こる場合は、コンビネータを書くことができます。私は許可されたセットから複数のトークンを認めて、実際に与えられたキーワードの受け入れ可能性を確認するために非解析的なアプローチを使用する作品を書くだろう。より簡単な文法を可能にすることに加えて、間違った使い方に関する診断を出した後で、より簡単に構文解析を続けることができます。

ランドール・シュルツ

4

あなたは "パーサー。^?" を使用することができます演算子を使用して、重複する要素の解析要素のグループをチェックします。ここで

def tokens = tokenA | tokenB | tokenC 
    def uniqueTokens = (tokens*) ^? (
    { case t if (t == t.removeDuplicates) => t }, 
    { "duplicate tokens found: " + _ }) 

は、あなたが任意の順序で4人の大将のいずれかを入力することができますが、重複が発生した場合の解析に失敗した例です。

package blevins.example 

import scala.util.parsing.combinator._ 

case class Stooge(name: String) 

object StoogesParser extends RegexParsers { 
    def moe = "Moe".r 
    def larry = "Larry".r 
    def curly = "Curly".r 
    def shemp = "Shemp".r 
    def stooge = (moe | larry | curly | shemp) ^^ { case s => Stooge(s) } 
    def certifiedStooge = stooge | """\w+""".r ^? (
    { case s: Stooge => s }, 
    { "not a stooge: " + _ }) 

    def stooges = (certifiedStooge*) ^? (
    { case x if (x == x.removeDuplicates) => x.toSet }, 
    { "duplicate stooge in: " + _ }) 

    def parse(s: String): String = { 
    parseAll(stooges, new scala.util.parsing.input.CharSequenceReader(s)) match { 
     case Success(r,_) => r.mkString(" ") 
     case Failure(r,_) => "failure: " + r 
     case Error(r,_) => "error: " + r 
    } 
    } 

} 

そして、いくつかの使用例:

package blevins.example 

object App extends Application { 

    def printParse(s: String): Unit = println(StoogesParser.parse(s)) 

    printParse("Moe Shemp Larry") 
    printParse("Moe Shemp Shemp") 
    printParse("Curly Beyonce") 

    /* Output: 
    Stooge(Moe) Stooge(Shemp) Stooge(Larry) 
    failure: duplicate stooge in: List(Stooge(Moe), Stooge(Shemp), Stooge(Shemp)) 
    failure: not a stooge: Beyonce 
    */ 
}