加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 将解析器组合器应用于case类

发布时间:2020-12-16 18:02:03 所属栏目:安全 来源:网络整理
导读:我正在使用 Scala的 Parser Combinators来解析一个字符串(没有新行,人为的例子). 字符串由许多不同的部分组成,我想分别提取并填充案例类. case class MyRecord(foo: String,bar: String,baz: String,bam: String,bat: String)object MyParser extends scala.
我正在使用 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)

它不是那么酷,但不需要外部库.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读