将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实例,但是如果性能是一个问题,那么很容易改变). (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
