Introducing CodableCSV

CodableCSV is a multi-platform Swift package for parsing/writing CSV files providing:

  • Imperative row-by-row and field-by-field CSV reader/writer.
  • Declarative encoding/decoding through Swift's Codable adoption.
  • Support for multiple inputs/outputs (Strings, Data, File handles, Foundation's Streams, etc.) and Byte Order Markers (BOM).
  • Configurable row/field delimiters, escaping scalars, headers, and trim sets.
  • Configurable buffers supporting huge files (iteratively loading them in memory if necessary).

We just released 0.5.2 finally reaching full Codable adoption. Meaning, you can use CSVDecoder/CSVEncoder and request keyed or unkeyed container to iterate through a CSV file's rows or to iterate through the files within a row.

let decoder = CSVDecoder()
let result = try decoder.decode([Student].self, from: URL("~/Desktop/Students.csv")

Usage and configuration values mimics Foundation's JSON & PLIST strategies including some more such as decimalStrategy (to encode/decode Decimal types from/to String) or bufferStrategy.

Take a look to the README for a deeper explanation or check the Roadmap to see where we are taking it.

12 Likes

I also have my old CommonCoding which includes CSV. The more the merrier :partying_face:.

Hi @Lantua, I actually came across your project just before posting here and it is in my ToDo list to dive deeper in the code. Once I do, I will make sure to put it in the CSV projects comparison section I have in the README.

2 Likes

If anyone is interested in a parser that supports streaming, skelpo/CSV is also an option.

1 Like

does it automatically handle delimiters being present in values?

It does! I am assuming that the field containing the delimiter is escaped with an escaping scalar (commonly a double quote). For examples:

id,name,motto
1,Oscar,"Everything in moderation, including moderation"

If the field wouldn't include the double quotes, it would be interpreted as two fields, which would make the row have 4 fields, which subsequently would throw an error since the previous row has 3 fields and all CSV should have the same amount of fields :smile:

CodableCSV is extremely configurable and you can set the field delimiter, row delimiters and escaping scalar that you want, among other things.

1 Like

Oh cool. I will check this out too. Thanks for sharing!

I have compiled a small list of CSV imperative and declarative projects at the end of the README in popularity order (Github stars). You can find your projects there @Lantua and @calebkleveter. Hopefully I have been fair to everyone.

2 Likes

I've been using this for a while in a CLI tool we use at work. Very nice :+1:

1 Like

I am getting errors trying to install. Using cocoapods for a macOS project I get:

[!] The platform of the target xxxx (macOS 10.15) is not compatible with CodableCSV (0.4.0), which does not support macOS.

I have updated cocoapods (sudo gem install cocoapods), updated the repos (pod repo update), finally got it working by pointing it directly at your podspec (pod 'CodableCSV', :git => 'GitHub - dehesa/CodableCSV: Read and write CSV files row-by-row or through Swift's Codable interface.')

Hi @wheeliebin, thank you for reporting. I am already aware of this. I already have a ticket in Github that you can use to monitor the problem completion.

Long story short. I am not a Cocoapods user and the Cocoapods support was performed by a contributor. It seems there is already another package called "CodableCSV", so I need to go and "register". It will be resolve soon. Sorry for the inconvenience.

Thank you for this CSV library, Marcos. I'm using it in a new project to import a large table. The programming interface is pleasantly minimalistic (decoder configuration in closure) and blends well into my code.

1 Like

I appreciate the kind words @kaio and thank you for the PR :slightly_smiling_face:

I need to finally sit down and write the performance tips for Codable usage and some benchmark to round up the library. It is really crazy how much faster Codable code can be by just following some simple indications.

Cool project! I ocasionally encoded/decoded CSVs manually in previous projects and recently got tired of this and wrote my own (way smaller and less mature) library - only now I read of this :D Not the first CSV library I read about, but the first one using Codable.

Regarding the flattening problem of nested structures, I actually found a more convenient solution: my CSVEncoder and CSVDecoder classes can be configured with a keySeparator like " " or " - ". The header will then contain fields like "pet - nickname" (to steal an example from your README).

Check it out! CSVParse/CSVParseTests.swift at main · AnarchoSystems/CSVParse · GitHub

That is quite a neat idea @Anachron, thank you for sharing it. I am writing it down on the ideas project for further research.

I understand that for personal usage, the idea is quite useful; I do worry whether introducing it would cause too much of "deviation" from the canonical Codable usage. One of the cool things about using Codable is that you can use the same interface (i.e. init(from:) and encode(to:)) with multiple representations (JSON, PLIST, CSV, etc).

I'm making use of codable as well (i.e. your library is the first except mine that I see that uses codable for CSV). You pass the key separator to the toplevel encoder/decoder at initialization time, not to the codable instances. The test file I shared includes an example (the last test) with a fully synthesized codable conformance that demonstrates the bahaviour ;)