2014-01-25 83 views
1

我刚刚开始在Scala中使用解析器组合器,但在解析器中解析句子,比如“我喜欢Scala”。 (单词以空格或句点结尾(.))。使用Scala解析器组合器解析句子

我开始用下面的实现:

package example 

import scala.util.parsing.combinator._ 

object Example extends RegexParsers { 
    override def skipWhitespace = false 

    def character: Parser[String] = """\w""".r 

    def word: Parser[String] = 
    rep(character) <~ (whiteSpace | guard(literal("."))) ^^ (_.mkString("")) 

    def sentence: Parser[List[String]] = rep(word) <~ "." 
} 

object Test extends App { 
    val result = Example.parseAll(Example.sentence, "I like Scala.") 

    println(result) 
} 

背后使用guard()的想法是有一个期限定词尾,但不能消耗它,这样的句子可以。但是,解析器被卡住(添加log()显示它重复尝试wordcharacter解析器)。

如果我改变wordsentence定义如下,它分析了一句,但语法描述不看的权利,也不会工作,如果我尝试添加解析器第(rep(sentence))等

def word: Parser[String] = 
    rep(character) <~ (whiteSpace | literal(".")) ^^ (_.mkString("")) 

def sentence: Parser[List[String]] = rep(word) <~ opt(".") 

任何想法可能会发生在这里?

回答

1

但是,解析器卡住了(添加log()显示它重复尝试单词和字符解析器)。

rep组合子对应于Perl风格正则表示法中的*。这意味着它匹配或更多个字符。我想你想让它匹配一个或更多个字符。将其更改为rep1(对应于Perl风格的正则表达式中的+)应该可以解决该问题。

但是,您的定义对我来说似乎仍然有点冗长。为什么要解析单个字符而不是仅使用\w+作为单词的模式?以下是我会写:

object Example extends RegexParsers { 
    override def skipWhitespace = false 

    def word: Parser[String] = """\w+""".r 

    def sentence: Parser[List[String]] = rep1sep(word, whiteSpace) <~ "." 
} 

请注意,我用rep1sep解析由空格分隔字的非空列表。还有一个repsep组合器,但我认为你每个句子至少需要一个单词。

+0

谢谢。至于简化'word',你是对的,在这个例子中,你的解决方案更有意义。我试图解决的原始问题有一个更复杂的领域,其中'字符'的等价物有点复杂,需要指定它自己的解析器。 – ramnivas