scala – 将解析器组合器应用于case类
我正在使用
Scala的
Parser Combinators来解析一个字符串(没有新行,人为的例子).
字符串由许多不同的部分组成,我想分别提取并填充案例类. 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 进一步的信息:我正在解析的字符串非常冗长和复杂(实际上,它是一个完整的文件,包含很长的复杂字符串),因此更改为regexp是不可能的. 解决方法
它有可能与
Shapeless2库.对于给定的:
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) 您可以使用?的通用foldRight intead组合解析器: 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,car) 附:内置scala功能的问题在于它们构建了基于类型的二叉树,这种树难以遍历并变平为元组. Shapeless解决了这个问题 – 它有自己的基于原理的二叉树名为HList,它是类似的但有一些有趣的操作,比如转换为元组或case类(可能是基于宏的).在这个例子中,我使用foldLeft来构建Shapeless-hlist和for-comprehension(在解析器上扩展为flatMap)以组合解析器,因为它们具有monadic性质.在无形状中,您必须将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,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,car) 它不是那么酷,但不需要外部库. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |