将Scala中的CSV读入具有错误处理的类实例
发布时间:2020-12-16 19:01:21 所属栏目:安全 来源:网络整理
导读:我想在 Scala中读取CSV字符串/文件,以便给定一个case类C和一个错误类型Error,解析器填充一个Iterable [Either [Error,C]].有没有图书馆做这个或类似的东西? 例如,给定类和错误 case class Person(name: String,age: Int)type Error = String 和CSV字符串 Fo
我想在
Scala中读取CSV字符串/文件,以便给定一个case类C和一个错误类型Error,解析器填充一个Iterable [Either [Error,C]].有没有图书馆做这个或类似的东西?
例如,给定类和错误 case class Person(name: String,age: Int) type Error = String 和CSV字符串 Foo,19 Ro Bar,24 解析器将输出 Stream(Right(Person("Foo",1)),Left("Cannot read 'Ro'"),Right(Person("Bar",24))) 更新: 我认为我的问题不清楚,所以让我澄清一下:在Scala中有没有定义样板?给定任何案例类,有没有办法自动加载?我想以这种方式使用它: val iter = csvParserFor[Person].parseLines(lines) 解决方法
这是一个无懈可击的实现,与
your proposed example中的方法略有不同.这是基于我过去写过的一些代码,与实现的主要区别在于这一点更通用 – 例如实际的CSV解析部分被分解出来,因此很容易使用专用的库.
首先为一个多用途的读类型类(no Shapeless yet): import scala.util.{ Failure,Success,Try } trait Read[A] { def reads(s: String): Try[A] } object Read { def apply[A](implicit readA: Read[A]): Read[A] = readA implicit object stringRead extends Read[String] { def reads(s: String): Try[String] = Success(s) } implicit object intRead extends Read[Int] { def reads(s: String) = Try(s.toInt) } // And so on... } 然后为有趣的部分:一个类型类,提供从列表的字符串转换(可能会失败)到HList: import shapeless._ trait FromRow[L <: HList] { def apply(row: List[String]): Try[L] } object FromRow { import HList.ListCompat._ def apply[L <: HList](implicit fromRow: FromRow[L]): FromRow[L] = fromRow def fromFunc[L <: HList](f: List[String] => Try[L]) = new FromRow[L] { def apply(row: List[String]) = f(row) } implicit val hnilFromRow: FromRow[HNil] = fromFunc { case Nil => Success(HNil) case _ => Failure(new RuntimeException("No more rows expected")) } implicit def hconsFromRow[H: Read,T <: HList: FromRow]: FromRow[H :: T] = fromFunc { case h :: t => for { hv <- Read[H].reads(h) tv <- FromRow[T].apply(t) } yield hv :: tv case Nil => Failure(new RuntimeException("Expected more cells")) } } 最后让它与案例类一起工作: trait RowParser[A] { def apply[L <: HList](row: List[String])(implicit gen: Generic.Aux[A,L],fromRow: FromRow[L] ): Try[A] = fromRow(row).map(gen. from) } def rowParserFor[A] = new RowParser[A] {} 现在我们可以写下面的例子,例如使用OpenCSV: case class Foo(s: String,i: Int) import au.com.bytecode.opencsv._ import scala.collection.JavaConverters._ val reader = new CSVReader(new java.io.FileReader("foos.csv")) val foos = reader.readAll.asScala.map(row => rowParserFor[Foo](row.toList)) 如果我们有一个这样的输入文件: first,10 second,11 third,twelve 我们会得到以下内容: scala> foos.foreach(println) Success(Foo(first,10)) Success(Foo(second,11)) Failure(java.lang.NumberFormatException: For input string: "twelve") (请注意,这引发了每一行的Generic和FromRow实例,但是如果性能是一个问题,那么很容易改变). (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |