2014-01-25 81 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