我刚刚开始在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()
显示它反复尝试word
和character
解析器。)
如果我按如下所示更改word
和sentence
定义,它会解析句子,但语法描述看起来不正确,如果我尝试为段落添加解析器({ {1}})等。
rep(sentence)
这里可能有什么想法?
答案 0 :(得分:2)
然而,解析器卡住了(添加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
组合子,但我认为你每个句子至少需要一个单词。