使用解析器组合器丢弃剩余的输入

时间:2012-06-24 23:45:01

标签: scala parser-combinators

我只想解析以下字符串,直到END令牌然后忽略其余的字符串:

val input = """
0)
blah1
blah2
blah3
1)
blah4
blah5
END
blah6
"""

使用

object Pars extends RegexParsers {
  def strings: Parser[List[String]] = rep(str) <~ end
  def str:     Parser[String]       = ".*".r
  def end:     Parser[String]       = "END" <~ rep(".*".r)
}

Pars.parseAll(Pars.strings, input)

进入无限循环和OutOfMemoryError。我做错了什么,以及如何解决这个问题?

2 个答案:

答案 0 :(得分:4)

请勿使用parseAll。请改用parse

至于你遇到的问题,你在几个地方说了两次同样的事情:

rep(".*".r)

rep*都表示“任意数量的重复”。现在,.*匹配空字符串,因此rep继续匹配无限数量的空字符串。

以下是我如何重写它:

object Pars extends RegexParsers {
  def strings: Parser[List[String]] = 
    ( "END" ^^^ Nil 
    | ".+".r ~ strings ^^ { case head ~ tail => head :: tail }
    )
}

答案 1 :(得分:0)

object Pars extends RegexParsers { 
  def strings: Parser[List[String]] = rep(str) <~ "END"
  def str:     Parser[String]       = """.*\r?\n""".r ^? { 
    case s if !(s matches """END\r?\n""") => s.replaceAll("""[\r\n]""", "")
  }
}

Pars.parse(Pars.strings, input) // note parse, not parseAll
  //[9.4] parsed: List(0), blah1, blah2, blah3, 1), blah4, blah5)

关键是你无法在.*上匹配 - 你必须在.*\r?\n上匹配才能获得一行文字(Windows需要\r - 格式文件)。我也试过^.*$,我认为它会起作用,但事实并非如此。 ".*" <~ """\r?\n""".r也没有。

^?^^类似,但它需要部分功能。)

如果有人能让这更优雅,请告诉我!