Scala Parser - 消息长度

时间:2011-06-11 14:24:31

标签: parsing scala parser-combinators

我正在玩Scala的Parser库。我正在尝试为指定长度的格式编写解析器,后跟该长度的消息。例如:

x.parseAll(x.message, "5helloworld") // result: "hello", remaining: "world"

我不确定如何使用组合器来做到这一点。我首先想到的是:

def message = length ~ body

但显然身体取决于长度,我不知道该怎么做:p

相反,您可以将消息解析器定义为单个解析器(不是解析器的组合),我认为这是可行的(尽管我没有看过单个解析器是否可以拉几个元素?)。

无论如何,我是一个scala noob,我发现这很棒!)

3 个答案:

答案 0 :(得分:4)

您应该使用into或其缩写>>

scala> object T extends RegexParsers {
     |   def length: Parser[String] = """\d+""".r
     |   def message: Parser[String] = length >> { length => """\w{%d}""".format(length.toInt).r }
     | }
defined module T

scala> T.parseAll(T.message, "5helloworld")
res0: T.ParseResult[String] =
[1.7] failure: string matching regex `\z' expected but `w' found

5helloworld
      ^

scala> T.parse(T.message, "5helloworld")
res1: T.ParseResult[String] = [1.7] parsed: hello

使用时要小心优先级。例如,如果您在上述函数后面添加了“~resid”,则Scala会将其解释为length >> ({ length => ...} ~ remainder)而不是(length >> { length => ...}) ~ remainder

答案 1 :(得分:2)

这听起来不像是无上下文的语言,所以你需要使用flatMap:

def message = length.flatMap(l => bodyOfLength(n))

其中length的类型为Parser [Int],bodyOfLength(n)将基于repN,例如

def bodyWithLength(n: Int) : Parser[String] 
  = repN(n, elem("any", _ => true)) ^^ {_.mkString}

答案 2 :(得分:1)

我不会为此目的使用pasrer组合器。但是如果你必须或问题变得更复杂,你可以试试这个:

def times(x :Long,what:String) : Parser[Any] = x match {
case 1 => what;
case x => what~times(x-1,what);
}

如果你想要剩下的东西,请不要使用parseAll,使用解析。 你可以解析长度,将结果存储在一个可变字段x中(我知道很丑,但在这里很有用)并解析体x次,然后你得到解析的字符串,其余的保留在解析器中。