假设有两个解析器:p
& q
。
现在,给出以下代码:
val p1 = p | q
val p2 = "$" ~> p1 <~ "$"
发生了一些奇怪的事情。假设一些字符串:val input = "..."
parseAll(p1, input)
使用p
的解析结果成功,但是:
parseAll(p2, "$" + input +"$")
以q
的解析结果成功
订单很重要。我只想在q
失败后尝试p
。
有什么办法可以强制解析器在p
之前评估q
吗?
在仔细检查文档之后:
如果p | q
成功或p
成功,
q
会成功。 请注意,q
仅在p
失败为非致命(即允许回溯)时才会尝试。
所以我的代码应该可以工作 所以我尝试用一个简单的例子进行复制(我的原始代码也是特定于用例的,而且大多数都与这里不相关)。但并没有成功。相反,我设法提出了一个解析器,它应该成功时失败。在以下REPL会话中显示:
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_66).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.util.parsing.combinator._
import scala.util.parsing.combinator._
scala> object MyParser extends RegexParsers {
| val xyz = "xyz".r ^^ { case s => Right(s) }
| val any = "\\S+".r ^^ { case s => Left(s) }
| val either: Parser[Either[String,String]] = xyz | any
| val wrapped = "$" ~> either <~ "$"
| def parseMeATest1(input: String) = parseAll(either, input) match {
| case Success(Right(s),_) => println(s"right: $s")
| case Success(Left(s),_) => println(s"left: $s")
| case NoSuccess(msg, _) => println(msg)
| }
| def parseMeATest2(input: String) = parseAll(wrapped, input) match {
| case Success(Right(s),_) => println(s"right: $s")
| case Success(Left(s),_) => println(s"left: $s")
| case NoSuccess(msg, _) => println(msg)
| }
| }
defined object MyParser
scala> MyParser.parseMeATest1("xyz")
right: xyz
scala> MyParser.parseMeATest1("zzz")
left: zzz
scala> MyParser.parseMeATest2("$xyz$")
right: xyz
scala> MyParser.parseMeATest2("$zzz$")
`$' expected but end of source found
那么,我在这里错过了什么,或者这是scala解析组合器的错误?
问题是p
解析器消耗了尾随的$
字符,导致整体失败,但由于使用了回溯,因此q
不消耗$
字符的{{1}}成功完成