2012-06-24 23 views
1

我只是想解析以下字符串直到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异常。我做错了什么,以及如何解决这个问题?

回答

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 } 
    ) 
} 
+0

谢谢,这很有用。我已经拼凑在一起的东西,使用这个和senia的优秀答案我的另一个问题http://stackoverflow.com/a/11113833/770361 –

+0

谢谢丹尼尔,你更新的答案是伟大的!我认为应该有一些方法来自动处理行结束,但不知道如何。 –

+0

我发现这个问题:如果'END'令牌不存在,而不是解析失败,我们得到一个堆栈溢出。有任何想法吗? –

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也没有。

^?类似于^^不同的是它的部分功能。)

如果任何人都可以让这个更优雅,请让我知道!

+0

我看不出有什么理由与'\ r \ n'匹配。正则表达式解析器应该跳过它作为空格。我只是以不同的方式编写'strings':'“END”| “。*”。r〜strings ^^ {case“END”=>无案例other〜list => other :: list}'。 –

+0

我的评论中存在优先错误。看到我编辑的答案。 –