The mental model

Simple rules make scripts safer.

simplecsv deliberately keeps the data model small. Learn the few guarantees once, then compose transforms without guessing what a method did to the header or the original rows.

The data model

A SimpleCsv is a two-dimensional slice of strings:

type SimpleCsv [][]string

The first row is always the header row. A small file looks like this:

row 0: id, name, status
row 1: 101, Ana,  active
row 2: 102, Ben,  paused

Invariants

Guarantee What it means in a CLI
Unique headers Name-based APIs always address exactly one column. Duplicate headers are rejected when reading, creating, or renaming.
Uniform width Every row has the same number of cells as the header. Ragged input is rejected instead of silently shifting values.
All strings Numbers, dates, and booleans stay strings in storage. Parse only inside the operation that needs a typed value.
Copy-on-write Methods that change data return independent CSVs. Getters return copies, too, so callers cannot mutate internal rows by accident.

Field-first APIs

Column positions are useful at the lowest level, but most scripts should name the field they mean. These methods skip the header for you:

Keep or remove

  • Where
  • WhereFold
  • FilterByField
  • UniqueByFields

Change values

  • MapColumnByField
  • FillColumnByField
  • ReplaceInField
  • TrimSpace

Build shape

  • OnlyThisFields
  • RenameHeaders
  • MoveColumn
  • AddComputedColumn

Inspect values

  • Distinct
  • ValueCounts
  • GetColumnByField
  • EachDataRow

Case sensitivity

Equality filters are explicit: Where is case-sensitive, while WhereFold uses case-insensitive equality. The older find and match methods are case-insensitive by default; use their CaseSensitive variants when exact matching matters.

Safe input and output

Normal reads load the full CSV into memory, which keeps the API simple. For large or attacker-controlled input, use ReadCsvLimit with record and byte limits.

Writes are atomic and use mode 0600. Values are written verbatim by default. If output may be opened in a spreadsheet and contains untrusted values, call SanitizeFormulas before writing.

safe := input.SanitizeFormulas()
if err := safe.WriteCsvFileE("for-spreadsheet.csv"); err != nil {
    log.Fatal(err)
}

Booleans or errors

Short transforms often read cleanly with a result and an ok boolean:

filtered, ok := input.Where("status", "active")

When a failed field lookup or header collision needs to reach a user, use the selective error variants:

joined, err := customers.JoinE(orders, "id", "customer_id")
if err != nil {
    log.Fatal(err)
}

See the complete list on the API map.