2009-11-23 56 views
7

我正在编写一个应用程序,它将采用各种“命令”字符串。我一直在寻找Scala组合库来标记命令。我发现在很多情况下我想说:“这些标记是无序集,所以它们可以以任何顺序出现,有些可能不会出现”。语法,Scala解析组合器和无序集合

以我目前的语法知识,我必须定义序列的所有组合为这样的(伪语法):

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

所以我的问题是,考虑tokenA-C是独一无二的,是有一个较短的方式用语法来定义一组任意的顺序?

回答

3

有办法绕过它。例如,看看解析器here。它接受4个预先定义的数字,可能出现在其他任何其他数字中,但必须出现一次,且只能出现一次。

OTOH,你可以写一个组合子,如果这种模式经常发生:

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类链接到数据库”,因为:next tuesday“。因此,在scala风格中定义的通用规则类似于”token = alphanum〜':'〜repsep(alphanum,'')。但我确实需要以不同的方式处理特定的属性。 –

+0

你必须确定,同一个不会出现一次以上? – ziggystar

+0

是的,这是计划,一些属性是可选的,他们应该只出现一次。 –

0

我不知道你想要什么样的结构以支持,但我收集你应该指定一个更具体的语法。从另一个回答您的评论:

待办事项消息:链接Todo类数据库

我猜你不想接受类似

待办事项消息:数据库的Todo到链接类

因此,您可能想要定义一些消息级别的关键字,如“链接”和“到”...

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

我想你将不得不在这个级别定义你的语法。

1

我不会试图语法执行这一要求。我会写一个允许集合中有多个令牌的产品,然后使用非分析方法来确定实际给出的关键字的可接受性。除了允许使用更简单的语法之外,它还允许您在发布关于错误用法的诊断之后更轻松地继续解析。

兰德尔·舒尔茨

4

您可以使用 “解析器。^?”运算符来检查一组解析元素是否有重复。

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

下面是一个例子,可以让你按任意顺序输入任何四个臭皮匠,但失败如果遇到重复解析:

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 
    */ 
}