斯卡拉解析器令牌分隔符问题
我想为下面的命令定义一个语法。斯卡拉解析器令牌分隔符问题
action = todo
message = link todo to database
properties = [deadline: next tuesday, context: app.model]
当运行如下所定义的语法这个输入时,收到以下错误消息::
[1.27] parsed: Command(todo,link todo to database,List())
[1.36] failure: string matching regex `\z' expected but `:' found
todo link todo to database deadline: next tuesday context: app.model
^
至于
object ParserWorkshop {
def main(args: Array[String]) = {
ChoiceParser("todo link todo to database")
ChoiceParser("todo link todo to database deadline: next tuesday context: app.model")
}
}
第二命令作为应该标记化我可以看到它失败了,因为用于匹配消息的单词的模式与属性键:值对的模式几乎相同,所以解析器无法知道消息的结束位置并开始物业。我可以坚持起始令牌被用来为每个属性像这样解决这个问题:
todo link todo to database :deadline: next tuesday :context: app.model
但我宁愿保留命令接近自然语言越好。 我有两个问题:
错误信息实际上是什么意思? 而我将如何修改现有语法以适用于给定的输入字符串?
import scala.util.parsing.combinator._
case class Command(action: String, message: String, properties: List[Property])
case class Property(name: String, value: String)
object ChoiceParser extends JavaTokenParsers {
def apply(input: String) = println(parseAll(command, input))
def command = action~message~properties ^^ {case a~m~p => new Command(a, m, p)}
def action = ident
def message = """[\w\d\s\.]+""".r
def properties = rep(property)
def property = propertyName~":"~propertyValue ^^ {
case n~":"~v => new Property(n, v)
}
def propertyName: Parser[String] = ident
def propertyValue: Parser[String] = """[\w\d\s\.]+""".r
}
这很简单。当您使用~
时,您必须明白,已成功完成的单个解析器没有回溯。
因此,例如,message
将所有内容都放到了冒号之前,因为所有这些都是可接受的模式。接下来,properties
是property
的rep
,它需要propertyName
,但它只能找到冒号(第一个字符不会被message
吞噬)。所以propertyName
失败,property
失败。现在,如上所述,properties
是rep
,因此它以0次重复成功完成,然后使command
成功完成。因此,回parseAll
。 command
解析器成功返回,消耗了冒号前的所有内容。然后它会问这个问题:我们是否在输入的末尾(\z
)?不,因为下一个冒号。所以,它预期的结束输入,但得到了冒号。
您必须更改正则表达式,以便它不会消耗冒号前的最后一个标识符。例如:
def message = """[\w\d\s\.]+(?![:\w])""".r
顺便说一句,当你使用def
你强迫表达重新评估。换句话说,每次调用每个def都会创建一个解析器。正则表达式在每次处理它们所属的解析器时被实例化。如果您将所有内容更改为val
,则您的性能将得到提高。
请记住,这些东西定义为的解析器,他们不会运行它。运行解析器的是parseAll
。
感谢Daniel,非常清晰,写得很好的解释 – 2009-11-25 21:11:42
我认为你应该改变你的语法是这样的: todo“链接待办事项数据库”:截止日期:“下周二”:上下文:“应用程序。模型“ – ziggystar 2009-11-26 13:28:02
这是一个我想避免的解决方案,因为我想尽可能使Todo语法尽可能地接近自然语言。 – 2009-11-27 10:14:31