我正在玩Scala的Parser库。我正在尝试为指定长度的格式编写解析器,后跟该长度的消息。例如:
x.parseAll(x.message, "5helloworld") // result: "hello", remaining: "world"
我不确定如何使用组合器来做到这一点。我首先想到的是:
def message = length ~ body
但显然身体取决于长度,我不知道该怎么做:p
相反,您可以将消息解析器定义为单个解析器(不是解析器的组合),我认为这是可行的(尽管我没有看过单个解析器是否可以拉几个元素?)。
无论如何,我是一个scala noob,我发现这很棒!)
答案 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次,然后你得到解析的字符串,其余的保留在解析器中。