i'm looking @ using scala's parser combinators parse string (no newlines, contrived example).
the string made of many different parts want extract separately , populate case class.
case class myrecord(foo: string, bar: string, baz: string, bam: string, bat: string) object myparser extends scala.util.parsing.combinator.regexparsers { val foo: parser[string] = "foo" val bar: parser[string] = "bar" val baz: parser[string] = "baz" val bam: parser[string] = "bam" val bat: parser[string] = "bat" val expression: parser[myrecord] = foo ~ bar ~ baz ~ bam ~ bat ^^ { case foo ~ bar ~ baz ~ bam ~ bat => myrecord(foo, bar, baz, bam, bat) } } this works well, there way apply parts of matched results directly case class without deconstructing?
val expression: parser[myrecord] = foo ~ bar ~ baz ~ bam ~ bat ^^ myrecord further information: string i'm parsing quite long , complex (in reality, it's whole file full of long complex strings) changing regexp out of question.
it's possible shapeless2 library. given:
object myparser extends scala.util.parsing.combinator.regexparsers import myparser._ val foo: parser[string] = "foo" val bar: parser[string] = "bar" val car: parser[string] = "car" case class record(f: string, b: string, c: string) you can combine parsers using generic foldright intead of ~:
import shapeless._ object f extends poly2 { implicit def parser[t, u <: hlist] = at[parser[t], parser[u]]{(a, b) => {aa <- a; bb <- b} yield aa :: bb } } val p: parser[record] = (foo :: bar :: car :: hnil) .foldright(success(hnil))(f).map(generic[record].from) result:
scala> parseall(p, "foo bar car").get res50: record = record(foo,bar,car) p.s. problem built-in scala functionality built ~-based typed binary tree, hard traverse , flatten tuple. shapeless solves problem - has it's own ::-based binary tree called hlist, it's simmilar has interesting operations, convertion tuples or case classes (probably macro-based). in example use foldleft build shapeless-hlist , for-comprehension (expands flatmap on parser) combine parsers have monadic nature. in shapeless have define foldleft's handler set of generic implicits, can process generic input (like t or u).
you can reuse f object combine parsers in typesafe way (you can combine different types here - that's fine).
second, less generic, way is:
implicit class as2[a, b](t: parser[a ~ b]){ def ^^^^[t] (co: (a, b) => t) = t map {tt => val (a ~ b) = tt; co(a, b)} } implicit class as3[a, b, c](t: parser[a ~ b ~ c]){ def ^^^^[t] (co: (a, b, c) => t) = t map {tt => val (a ~ b ~ c) = tt; co(a, b, c)} } ... implicit class as21 ... usage:
scala> val p = foo ~ bar ~ car ^^^^ record p: myparser.parser[record] = parser () scala> parseall(p, "foo bar car").get res53: record = record(foo,bar,car) it's not cool, doesn't require external libraries.
Comments
Post a Comment