不容易,因为成功的匹配不会重试。例如:
object X extends RegexParsers {
def p = ("a" | "aa" | "aaa" | "aaaa") ~ "ab"
}
scala> X.parseAll(X.p, "aaaab")
res1: X.ParseResult[X.~[String,String]] =
[1.2] failure: `ab' expected but `a' found
aaaab
^
第一个匹配成功了,位于括号内的解析器进行了下一步。那个失败了,所以p
也失败了。如果p
是备选匹配的一部分,那么将尝试备选方案,因此关键是要产生能够处理这种情况的东西。
假设我们有以下内容:
def nonGreedy[T](rep: => Parser[T], terminal: => Parser[T]) = Parser { in =>
def recurse(in: Input, elems: List[T]): ParseResult[List[T] ~ T] =
terminal(in) match {
case Success(x, rest) => Success(new ~(elems.reverse, x), rest)
case _ =>
rep(in) match {
case Success(x, rest) => recurse(rest, x :: elems)
case ns: NoSuccess => ns
}
}
recurse(in, Nil)
}
您可以像这样使用它:
def p = nonGreedy("a", "ab")
顺便说一下,我发现查看其他事物的定义对于尝试想出像上面的
nonGreedy
这样的东西是有帮助的。特别是,请查看
rep1
是如何定义的,以及它是如何更改以避免重新评估其重复参数的-相同的方法可能对
nonGreedy
也有用。
这是一个完整的解决方案,并进行了一些更改,以避免消耗“终端”。
trait NonGreedy extends Parsers {
def nonGreedy[T, U](rep: => Parser[T], terminal: => Parser[U]) = Parser { in =>
def recurse(in: Input, elems: List[T]): ParseResult[List[T]] =
terminal(in) match {
case _: Success[_] => Success(elems.reverse, in)
case _ =>
rep(in) match {
case Success(x, rest) => recurse(rest, x :: elems)
case ns: NoSuccess => ns
}
}
recurse(in, Nil)
}
}
class Arith extends RegexParsers with NonGreedy {
val select: Parser[String] = "(?i)SELECT".r
val from: Parser[String] = "(?i)FROM".r
val token: Parser[String] = "(\\s*)\\w+(\\s*)".r
val eof: Parser[String] = """\z""".r
def selectstatement: Parser[Any] = selectclause(from) ~ fromclause(eof)
def selectclause(terminal: Parser[Any]): Parser[Any] =
select ~ tokens(terminal)
def fromclause(terminal: Parser[Any]): Parser[Any] =
from ~ tokens(terminal)
def tokens(terminal: Parser[Any]): Parser[Any] =
nonGreedy(token, terminal)
}
*
、+
和?
运算符始终表现出贪婪行为,尽可能消耗尽量多的输入并且不进行回溯:表达式a*
将始终消耗在输入字符串中连续可用的 a,导致(a* a)
总是失败。 - Little Alien