2

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

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

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

def message = length ~ body

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

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

无论如何,我是一个 scala 菜鸟,我只是觉得这太棒了:)

4

3 回答 3

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

使用时要注意优先级。例如,如果在上面的函数之后添加“~ 余数”,Scala 会将其解释为length >> ({ length => ...} ~ remainder)而不是(length >> { length => ...}) ~ remainder.

于 2011-06-11T18:58:22.070 回答
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}
于 2011-06-11T15:35:40.940 回答
1

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

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

如果你想保留一些东西,不要使用 parseAll,使用 parse。您可以解析长度,将结果存储在可变字段 x 中(我知道很难看,但在这里很有用)并解析主体 x 次,然后解析字符串,其余部分保留在解析器中。

于 2011-06-11T15:54:26.283 回答