Name: csvside
Owner: Underscore
Description: CSV reader and writer combinators for Scala. Made with Cats.
Created: 2015-07-18 20:15:15.0
Updated: 2018-03-28 14:53:09.0
Pushed: 2018-03-28 14:53:10.0
Size: 95
Language: Scala
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
CSV readers and combinators for Scala. Made with Cats.
Copyright 2015 Richard Dallaway and Dave Gurnell. Licensed Apache 2.
Grab the code by adding the following to your build.sbt
:
aryDependencies += "io.underscore" %% "csvside" % "<<VERSION>>"
Here's an example that reads directly from a String
.
You can also read from a java.io.File
or a java.io.Reader
:
e want to parse this CSV...
csv = """
tr,Bool,Int
bc,true,123
a b",false,321
,
bc,abc,abc
trim.stripMargin
o a sequence of this data structure...
class Test(str: String, num: Int, bool: Option[Boolean])
e import Csvside...
rt csvside._
e define a RowFormat...
rt cats.syntax.cartesian._
icit val testFormat: RowFormat[Test] = (
tr".csv[String] |@|
nt".csv[Int] |@|
ool".csv[Option[Boolean]]
ap(Test.apply)(unlift(Test.unapply))
e read the data...
ans = Csv.fromString[Test](csv).toList
ns: List[csvside.CsvValidated[Test]] = List(
Valid(Test(abc,123,Some(true))),
Valid(Test(a b,321,Some(false))),
Invalid(List(CsvError(4,Int,Must be a whole number))),
Invalid(List(CsvError(5,Int,Must be a whole number),
CsvError(5,Bool,Must be a yes/no value or blank))))
nd we write it back to CSV...
rt cats.data.Validated
validOnly = ans collect { case Validated.Valid(test) => test }
finalCsv = Csv.toString(validOnly)
inalCsv: String =
"Str","Int","Bool"
abc","123","true"
a b","321","false"
If the format of the rows depends on the values in the header row,
we can use a ListReader[A]
to generate a ColumnReader[A]
on the fly:
e want to parse the cells in this CSV...
csv = s"""
ow,Col1,Col2,Col3
,1,2,3
,,,
,3,,1
trim.stripMargin
o a sequence of this data structure...
class Test(key: String, values: Map[CsvPath, Option[Int]])
e do this by creating a `ListReader` that
arses the column headings and creates a `ColumnReader`
o read the rest of the file.
e import from Csvside...
rt csvside._
e define a ListReader...
rt cats.data.Validated.{valid, invalid}
rt cats.syntax.cartesian._
rt cats.syntax.validated._
icit val testReader: ListReader[Test] =
stReader[Test] {
case head :: tail =>
(head.read[String] |@| tail.readMap[Option[Int]]).map(Test.apply).valid
case Nil =>
invalid(List(CsvError(1, "", "File must contain at least one column")))
nd we read the data...
ans = Csv.fromString[Test](csv).toList
ns: List[CsvValidated[Test]] =
List(
Valid(Test("x", Map("Col1" -> Some(1), "Col2" -> Some(2), "Col3" -> Some(3)))),
Valid(Test("y", Map("Col1" -> None, "Col2" -> None, "Col3" -> None))),
Valid(Test("z", Map("Col1" -> Some(3), "Col2" -> None, "Col3" -> Some(1)))))