#scala #parsing #parser-combinators
Вопрос:
С помощью комбинаторов scala-синтаксического анализатора, как я могу проанализировать 42
содержимое следующего документа?
1 Turning and turning in the widening gyre
2 The falcon cannot hear the falconer;
3 Things fall apart; the centre cannot hold;
4 Mere anarchy is loosed upon the world,
5 The blood-dimmed tide is loosed, and everywhere
6 The ceremony of innocence is drowned;
7 The best lack all conviction, while the worst
8 Are full of passionate intensity.
42
class PoemParser extends RegexParsers
{
def textLine: Parser[Unit] = ".*[^ ] .*n".r ^^^ {}
def blankLine: Parser[Unit] = "\h*n".r ^^^ {}
def intLine: Parser[Int] = "\d n".r ^^ { _.trim.toInt }
def meaning: Parser[Int] = rep(textLine | blankLine) ~> intLine
}
object RunPoemParser extends PoemParser with App {
val poem =
"""
|1 Turning and turning in the widening gyre
|2 The falcon cannot hear the falconer;
|3 Things fall apart; the centre cannot hold;
|4 Mere anarchy is loosed upon the world,
|5 The blood-dimmed tide is loosed, and everywhere
|6 The ceremony of innocence is drowned;
|7 The best lack all conviction, while the worst
|8 Are full of passionate intensity.
|
|42
|""".stripMargin
parse(meaning, poem) match {
case Success(matched, _) => println(matched.toString)
case Failure(msg, _) => println("FAILURE: " msg)
case Error(msg, _) => println("ERROR: " msg)
}
}
Проблема , конечно, в том, что textLine
синтаксический анализатор также совпадает "42n"
, поэтому он жадно поглощает каждую строку, прежде чем intLine
у синтаксического анализатора появится шанс сопоставить ее.
В этом простом примере я могу создать специальный сопоставитель только для первых восьми строк (что-то вроде \d .*n".r
). Но как мне решить эту проблему в целом? Какую комбинацию guard
not
, ~!
, или других операторов/методов я должен использовать , чтобы не жадно потреблять произвольное количество токенов, прежде чем сопоставлять тот, который я хочу?