CoxProgramming.CSV
1.2.2
dotnet add package CoxProgramming.CSV --version 1.2.2
NuGet\Install-Package CoxProgramming.CSV -Version 1.2.2
<PackageReference Include="CoxProgramming.CSV" Version="1.2.2" />
<PackageVersion Include="CoxProgramming.CSV" Version="1.2.2" />
<PackageReference Include="CoxProgramming.CSV" />
paket add CoxProgramming.CSV --version 1.2.2
#r "nuget: CoxProgramming.CSV, 1.2.2"
#:package CoxProgramming.CSV@1.2.2
#addin nuget:?package=CoxProgramming.CSV&version=1.2.2
#tool nuget:?package=CoxProgramming.CSV&version=1.2.2
Csv.CSV Class Documentation
Overview
The Csv.CSV
class provides a flexible, in-memory representation of a CSV (Comma-Separated Values) document. It supports reading, writing, querying, and manipulating tabular data, with robust handling for quoted values, custom delimiters, and dynamic columns. The class is designed for .NET 9 and C# 13.0.
Key Features
- Read/Write CSV: Load from and save to files or streams, with support for custom delimiters.
- Dynamic Columns: Columns are inferred from the union of all row keys.
- Row Access: Index rows by number, column name, or key-value pairs.
- Querying: Filter rows by values or regular expressions.
- Export: Convert to JSON, HTML table, or C# record code.
- Type Inference: Guess column data types (int, double, DateTime, string).
- Bulk Operations: Add, remove, or compare rows and tables.
Usage Example
Constructors
CSV()
: Initializes an empty CSV.CSV(string heading)
: Initializes with a heading.CSV(IEnumerable<Row> data)
: Initializes from a collection of rows.CSV(Stream inputStream, Delimeter delimeter = default)
: Loads from a stream.
Factory Methods
static CSV Open(string fileName, Delimeter delimeter = default)
static CSV Open(Stream stream, Delimeter delimeter = default)
static CSV CreateFrom(IEnumerable<Row> rows)
Properties
string Heading
Optional heading/title for the table.List<string> AllKeys
List of all column headers (union of all row keys).int ColCount
Number of columns.int RowCount
Number of rows.string JsonString
JSON representation of the table.
Indexers
Row this[int index]
Access row by index.List<string> this[string column]
Get all values in a column.Row this[string column, string value]
Get the first row whererow[column] == value
.CSV this[Row primaryKey]
Get all rows matching the key-value pairs inprimaryKey
.CSV this[Dictionary<string, Regex> primaryKey]
Get all rows matching the regex patterns for each column.
Methods
void Add(Row row)
Add a row.void Add(CSV other)
Add all rows from another CSV.void Remove(Row row)
Remove all rows matching the given row's key-value pairs.bool Contains(Row row)
Check if a row exists.CSV NotIn(CSV other)
Get rows not present in another CSV.List<string> GetColumn(string header)
Get all values in a column.Row GetRow(string header, string key)
Get the first row whererow[header] == key
.bool ContainsNulls(string column)
Check if a column contains "null" values.string ToCSharpRecordCode(string typeName, string accessLevel = "public")
Generate a C# record definition for the table.Type GetDataType(string column)
Infer the .NET type for a column.string GuessMySqlDataType(string column)
Guess the MySQL data type for a column.void Save(string fileName, Delimeter delimeter = default)
Save to a file.void Save(Stream output, Delimeter delimeter = default, bool leaveStreamOpen = false)
Save to a stream.string HtmlTable(string tableCssClass = "", string headerRowCssClass = "", string rowCssClass = "")
Export as an HTML table.
Delimeter Support
The Delimeter
struct supports:
- Comma (
,
) - Semicolon (
;
) - Tab (
\t
) - Tilde (
~
)
You can specify a delimiter when reading or writing CSV files.
Row Class
Each row is a Row
object, which extends Dictionary<string, string>
.
- Access values by column name:
row["ColumnName"]
- Converts to JSON via
row.JsonString
Row Data Extraction Methods
Row.SplitColumn
Splits a single column's value into multiple columns using a regular expression with capture groups.
Signature:
Row SplitColumn(string column, Regex extractionExpression, int multimatchIndex = 0)
column
: The name of the column to split.extractionExpression
: ARegex
with named capture groups for each new column to extract.multimatchIndex
: If the regex matches multiple times, which match to use (default is 0, the first match).- Returns: A new
Row
containing only the extracted columns.
Example:
// Suppose a row has a column "FullName" with value "Doe, John"
var row = new Row { ["FullName"] = "Doe, John" };
var regex = new Regex(@"(?<Last>[^,]+), (?<First>.+)");
Row extracted = row.SplitColumn("FullName", regex);
// extracted["First"] == "John", extracted["Last"] == "Doe"
Row.MultiSplitColumn
Splits a single column's value into multiple rows, each with columns from regex capture groups, for every match in the value.
Signature:
CSV MultiSplitColumn(string column, Regex extractionExpression)
column
: The name of the column to split.extractionExpression
: ARegex
with named capture groups for each new column to extract.- Returns: A
CSV
where each row corresponds to a match of the regex in the column value.
Example:
// Suppose a row has a column "Phones" with value "Home:123-4567;Work:987-6543"
var row = new Row { ["Phones"] = "Home:123-4567;Work:987-6543" };
var regex = new Regex(@"(?<Type>\w+):(?<Number>\d+-\d+)");
CSV phoneRows = row.MultiSplitColumn("Phones", regex);
// phoneRows will have two rows:
// ["Type"] = "Home", ["Number"] = "123-4567"
// ["Type"] = "Work", ["Number"] = "987-6543"
LINQ Support
The Csv.CSV
class fully supports LINQ (Language Integrated Query) because it implements IEnumerable<Row>
. This allows you to use all standard LINQ extension methods (Where
, Select
, OrderBy
, GroupBy
, etc.) directly on your CSV
instances and their rows.
LINQ Usage Examples
Filtering Rows
You can filter rows using LINQ's Where
:
using Csv; using System.Linq;
// Load a CSV file
CSV table = CSV.Open("data.csv");
// Find all rows where the "Status" column is "Active"
var activeRows = table.Where(row => row["Status"] == "Active");
// Convert the result to a list or a new CSV List<Row> activeList = activeRows.ToList(); CSV activeTable = new CSV(activeRows);
Projecting Columns
You can select specific columns or transform data:
// Get all email addresses from the "Email" column var emails = table.Select(row => row["Email"]).ToList();
Ordering and Grouping
You can order or group rows by any column:
// Order rows by the "LastName" column
var ordered = table.OrderBy(row => row["LastName"]);
// Group rows by the "Department" column
var grouped = table.GroupBy(row => row["Department"]);
Aggregation
You can perform aggregations, such as counting or summing:
// Count rows where "Score" > 90
int highScoreCount = table.Count(row => int.Parse(row["Score"]) > 90);
// Sum a numeric column
int total = table.Sum(row => int.Parse(row["Amount"]));
Notes
- Each
Row
is aDictionary<string, string>
, so you can use dictionary accessors in your LINQ queries. - You can chain LINQ queries for complex data processing.
- After filtering or projecting, you can create a new
CSV
instance from anyIEnumerable<Row>
.
Example: Creating a Filtered CSV
// Filter and save only rows with non-null "Email"
var filtered = table.Where(row =>
!string.IsNullOrWhiteSpace(row["Email"]));
CSV filteredCsv = new CSV(filtered);
filteredCsv.Save("filtered.csv");
Summary:
The CSV library is designed to work seamlessly with LINQ, enabling expressive, type-safe, and efficient data queries and transformations on tabular data.
Advanced: Custom Row Types
Creating a CSV from DTOs
You can create a new CSV from a collection of DTOs:
public record Person(int Id, string Name, string Email)
{
// Convert from Row to Person public static
implicit operator Person(Row row) =>
new Person( int.TryParse(row["Id"], out var id) ? id : 0, row["Name"], row["Email"] );
// Convert from Person to Row
public static implicit operator Row(Person p) => new Row
{
["Id"] = p.Id.ToString(),
["Name"] = p.Name,
["Email"] = p.Email
};
}
Usage in LINQ Queries
You can now use these conversions in LINQ queries for type-safe access:
CSV table = CSV.Open("people.csv");
// Convert all rows to Person records
var people = table.Select(row => (Person)row).ToList();
// Filter and project using DTOs
var emails = table
.Select(row => (Person)row)
.Where(person => person.Email.EndsWith("@example.com"))
.Select(person => person.Email)
.ToList();
Creating Rows from DTOs
You can also convert DTOs back to Row
for adding or updating CSV data:
var newPerson = new Person(42, "Alice", "alice@example.com");
Row row = newPerson; // Implicit conversion
table.Add(row);
Creating a CSV from DTOs
You can create a new CSV from a collection of DTOs:
List<Person> people = GetPeople();
CSV csv = [..people.Select(p => (Row)p))];
Summary:
Using implicit conversions between DTO records and Row
enables type-safe, expressive, and maintainable code when working with CSV data and LINQ.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.