Example of parser combinator.
object Tmp {
def main(args: Array[String]) = {
val parser = new JsPageDataParser
parser.parse(
"""
|var matchCentreData = {"a":{"xx":"fsdf","aa":{"aaa":"bbb","ccc":"ddd"}}}
""".stripMargin.trim)
}
}
/**
* Created on 16.06.15.
*/
class JsPageDataParser {
val parser = new JsParser
def parse(content: String) = {
val result = parser.parseAll(parser.matchCentreData, content).get
println("DONE:")
println(result)
}
}
class JsParser extends RegexParsers {
val strLiteral = "[^:\"]+".r
def matchCentreData: Parser[Seq[NestedMap]] = "var matchCentreData = " ~> jsDict
def jsDict: Parser[Seq[NestedMap]] = "{" ~> repsep(keyValue, ",") <~ "}"
def keyValue: Parser[NestedMap] = (("\"" ~ strLiteral ~ "\":" ~ mapValue) ^^ {
case "\"" ~ mapKey ~ "\":" ~ mapVal =>
NestedMap(Map(mapKey -> mapVal))
})
def mapValue: Parser[Either[String, NestedMap]] = (jsDict | quoted) ^^ {
case str: String => Left(str)
case dict: Seq[NestedMap] => Right(dict.foldLeft(NestedMap(Map.empty)) {
case (agg, map) => NestedMap(agg.kvs + (map.kvs.head))
})
}
// x~>y<~z despite arrow directions alway has order of matching from left to right
// so be careful not to eat in y every char
def quoted: Parser[String] = "\"" ~> strLiteral <~ "\""
}
case class NestedMap(kvs: Map[String, Either[String, NestedMap]])