Project Description

Parsing a CSV file is a very common task and has been implemented by an extensive number of libraries. In some cases, however, all you need is a library that is simple and straightforward. This is the precisely what Toolkit.Csv sets out to accomplish, providing a simple way to parse a string into a 2D array of values, because sometimes this is all you need. Other libraries require classes with custom field attributes to map values to, but in some situations (i.e. when the number of columns is unknown) this is not suitable. Toolkit.Csv solves this problem by presenting your data in a standard format that can be translated into whichever format is best for your situation.

Most importantly, we have taken careful attention to adhere to the CSV specification, ensuring compatibility with well-formed CSV files. This library supports almost any separator for non-standard CSV implementations. See the specification below for a full detailed summary.

>> Download Toolkit.Csv from NuGet <<

 

CSV Specification

The specification we have followed is listed below in a simplified form, based off of that of SuperCSV. Note that this implementation supports *nix and Windows style line endings as well as a user-defined separator.

file         ::= { line } lastLine
line         ::= [ entry { separator entry } ] newline
lastLine     ::= [ entry { separator entry } ] [newline]
entry        ::= { character | whitespace } 
	     | " { character | whitespace | separator | newline | escapedQuote } "
newline      ::= "\n" | "\r\n"
separator    ::= <user-defined>
character    ::= all characters - (separator | newline | quote | whitespace)
whitespace   ::= ' '
quote        ::= "
escapedQuote ::= ""

This sample CSV file demonstrates the above rules:

hello, world!
two words,"or quoted"
   ignores  spaces,at    ends
"escape ""quotes"" like this"
"this, is,
one, value."

Would produce the following result:

hello world!
two words or quoted
ignores spaces at    ends
escape "quotes" like this  

this, is,
one, value.

 

 

Example Usage

// Read the data into a 2d array
// You can choose a different separator optionally
string[][] data = CsvParser.ParseFile(',', "data.csv");

// Now do whatever you want with the data
foreach (var record in data) {
    // ... record is a row in the csv file
}

// Parse an input stream as Dictionaries
Dictionary<string,string>[] dicts = CsvParser.ParseStreamAsDictionaries(',', dataStream);

// Results are dictionaries with each field mapped to the column header
foreach (var recordDict in dicts) {
    Person p = new Person();
    p.name = recordDict["name"];
    p.address = recordDict["address"];
    // ... etc
}

// Parse a CSV string as dynamic objects
ExpandoObject[] dynamics = CsvParser.ParseTextAsDynamics(',', dataString);

// Results are dynamic objects with fields mapped to the column headers
foreach (dynamic recordDynamic in dynamics) {
    SendWelcomeEmail(recordDynamic.email_address, recordDynamic.name);
    // ... etc
}

// Class to store packages
class Package {
    public string id { get; set; }
    public DateTime pubDate {get; set; }
    public int? copyrightYear { get; set; }
}

// Load a list of packages from a CSV file
Package[] pkgs = CsvParser.ParseFileAs<Package>(',', "pkglist.csv")

In general, functions follow the format:

 

parse{Input}As{Output}

Input  ::= Text | File | Stream | Reader
Output ::= Array | Dictionaries | Dynamics | CustomType

 

Implemenation

Uses FsLex and FsYacc constructs to parse the CSV contents quickly and efficiently.

Last edited Jul 10, 2012 at 7:34 PM by Eikos, version 13