私は自分が抱えているこの問題を盲目的に見つめてきましたが、これはおそらく本当にばかげた質問になると思います. しかし、私は自分のプライドを飲み込まなければなりません。
思ったようにバックトラックしないこのコンビネーターパーサーがあります。コンテキストを完全に削除することなく、小さな例に減らしてきました。「foobar」のように感じます-例は読みにくいだけです. ここに行きます:
@RunWith(classOf[JUnitRunner])
class ParserBacktrackTest extends RegexParsers with Spec with ShouldMatchers {
override def skipWhitespace = false
lazy val optSpace = opt(whiteSpace)
lazy val number = """\d+([\.]\d+)?""".r
lazy val numWithOptSpace = number <~ optSpace
private def litre = numWithOptSpace <~ ("litre" | "l")
def volume = litre ^^ { case _ => "volume" }
private def namedPieces = numWithOptSpace <~ ("pcs") ^^ { case _ => "explPcs" }
private def implicitPieces = number ^^ { case _ => "implPcs" }
protected def unitAmount = namedPieces | implicitPieces
def nameOfIngredient = ".*".r
def amount = volume | unitAmount
// def amount = unitAmount
protected def ingredient = (amount <~ whiteSpace) ~ nameOfIngredient
describe("IngredientParser") {
it("should parse volume") {
shouldParse("1 litre lime")
}
it("should parse explicit pieces") {
shouldParse("1 pcs lime")
}
it("should parse implicit pieces") {
shouldParse("1 lime")
}
}
def shouldParse(row: String) = {
val result = parseAll(ingredient, row)
result match {
case Success(value, _) => println(value)
case x => println(x)
}
result.successful should be(true)
}
}
したがって、3 番目のテストは失敗します。
(volume~lime)
(explPcs~lime)
[1.4] failure: string matching regex `\s+' expected but `i' found
1 lime
^
そのため、 l が消費されたようで、litre-parser
スペースが見つからなかったときに失敗しました。しかし、その時は後戻りして、次の生産ルールを試すだろうと思っていたでしょう。前のボリューム パーサーを削除 (コメントを削除) すると成功するため、明らかにimplicitPieces
パーサーはこの行を解析します。
(implPcs~litre lime)
(explPcs~lime)
(implPcs~lime)
なぜamount
後戻りしないのですか?私は何を誤解していますか?