私はScalaの使い方を見ています パーサコンビネータ 文字列を解析します(改行なし、考案例)。
文字列は、別々に抽出してケースクラスを生成したいさまざまな部分で構成されています。
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)
}
}
これは完全にうまく機能しますが、一致した結果の一部を分解しないでケースクラスに直接適用する方法はありますか?
val expression: Parser[MyRecord] =
foo ~ bar ~ baz ~ bam ~ bat ^^ MyRecord
さらに詳しい情報: 私が解析する文字列は非常に長く複雑です(実際には、長い複雑な文字列でいっぱいになったファイルです)ので、正規表現に変更することは問題外です。
回答:
回答№1は5それは可能です 無形2 としょうかん。与えられたために:
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)
genericを使ってパーサを組み合わせることができます foldRight
の ~
:
import shapeless._
object f extends Poly2 {
implicit def parser[T, U <: HList] =
at[Parser[T], Parser[U]]{(a, b) =>
for {aa <- a; bb <- b} yield aa :: bb
}
}
val p: Parser[Record] = (foo :: bar :: car :: HNil)
.foldRight(success(HNil))(f).map(Generic[Record].from)
結果:
scala> parseAll(p, "foo bar car").get
res50: Record = Record(foo,bar,car)
P.S組み込みのスカラ機能の問題は、それらが構築したことです。 ~
トラバースが困難でタプルにフラット化された、ベースの型付きバイナリツリー。 Shapelessはこの問題を解決します - それはそれ自身を持っています ::
ベースの二分木 HList
これは似ていますが、タプルやケースクラスへの変換(おそらくマクロベース)のような興味深い操作があります。 foldLeft
Shapeless-hlistとfor-jamhension(を展開する flatMap
それらはモナド的な性質を持っているのでパーサーを組み合わせる)。形のないあなたが定義する必要があります foldLeft
一般的な暗黙の集合としてのハンドラ T
または U
)。
あなたは私のものを再利用できます f
タイプパーフェクトな方法でパーサーを結合するためのオブジェクト(あなたはここでも異なるタイプを結合することができます。
第二に、あまり一般的ではない、方法は次のとおりです。
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 ...
使用法:
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)
それほどクールではありませんが、外部ライブラリを必要としません。