CSV Cleaner

Paste a messy CSV and tidy it without opening a spreadsheet: trim stray spaces, drop blank and duplicate rows, filter, sort and keep only the columns you need. Every step is a checkbox, the output updates as you click, and the stats show how many rows each step removed. Semicolon, tab and pipe files work too, and the output keeps whichever delimiter the input used.

CSV Input
Operations (applied top to bottom)
3. Filter rows
5. Sort
6. Keep columns /

Columns appear once you paste a CSV.

Cleaned CSV

1 CSV Cleaner example

Messy export

email,name,plan,seats,signed_up
  ada@example.com ,Ada Lovelace,pro,12,2024-03-02
grace@example.com,Grace Hopper,team,40,2023-11-19
,,,,
bob@example.com,Bob Tables,free,1,2024-06-30
grace@example.com,Grace Hopper,team,40,2023-11-19
alan@example.com,  Alan Turing,pro,3,2022-01-15
"lin@example.com","Lin, Mei",team,9,2024-02-08
ada@example.com,Ada Lovelace,pro,12,2024-03-02

Cleaned: free plans excluded, sorted by seats descending

email,name,seats
grace@example.com,Grace Hopper,40
ada@example.com,Ada Lovelace,12
lin@example.com,"Lin, Mei",9
alan@example.com,Alan Turing,3

Settings used: trim on, empty rows removed, filter plan excluding free, duplicates removed by whole row, sort by seats descending, keep email, name and seats. Eight rows in, four out: one empty, one filtered, two duplicates, and the untrimmed ada@example.com only matches its twin because trimming ran first.

2 What each step does

Trim and empty rows

Trim strips leading and trailing whitespace from every cell, header included. A row counts as empty when every cell is blank after that, so ,,,, goes too.

Filter

A plain substring match, case-insensitive unless you tick Match case. Pick Any column to search the whole row. Exclude matches flips it into a "drop rows containing" filter. No regex, no wildcards.

Duplicates

By whole row, two rows must match cell for cell. By a key column, only that column is compared and the first row with each value wins. Comparison is exact, so Bob and bob are different.

Sort

Numbers sort as numbers (9 before 10, 1,200 read as 1200). Text uses a natural, case-insensitive order so item2 comes before item10. Blank cells go last either way, and ties keep their original order.

3 What it will not touch

Values are never reformatted. Leading zeros, long IDs and values that look like dates come out exactly as they went in, which is the main reason to clean a CSV outside a spreadsheet. Quoting in the output is minimal: a field gets quotes only if it contains the delimiter, a double quote or a line break. The delimiter and line endings of the input are kept.

Dates are sorted as text. That works for ISO dates like 2024-03-02, but 03/02/2024 sorts by month or day before year, so the order comes out wrong. Everything runs in your browser, so the practical limit is memory: a file of a few hundred thousand rows is fine on a laptop, a multi-gigabyte dump is a job for csvkit or a database.

How to use the CSV Cleaner tool

  1. Paste a CSV into CSV Input or click Upload CSV. Dummy Data loads a messy example with spaces, blank lines and duplicates.
  2. Check the Delimiter (Auto-detect usually gets it) and First row is header. The column pickers fill in from the header.
  3. Work down the Operations panel: trim, remove empty rows, filter by text in a column, remove duplicates by whole row or key column, and sort.
  4. Untick columns under Keep columns to drop them. All and None toggle every column at once.
  5. Read the counts above the output (rows in, rows out, empty, filtered, duplicates), then click Copy or Download.
  6. If the file came from Excel in a European locale, pick Semicolon (;) in the Delimiter menu. The output keeps that delimiter, so Excel opens it the same way afterwards.

How to clean a CSV in JavaScript and Python

JavaScript

// rows: array of arrays from any CSV parser (csv-parse, papaparse, the one above)
function clean(rows, { key = null, sortBy = null, desc = false, keep = null } = {}) {
  const [header, ...body] = rows;
  let out = body
    .map((r) => r.map((c) => c.trim()))
    .filter((r) => r.some((c) => c !== ""));

  const seen = new Set();
  out = out.filter((r) => {
    const k = key === null ? JSON.stringify(r) : r[key];
    return seen.has(k) ? false : (seen.add(k), true);
  });

  if (sortBy !== null) {
    const coll = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" });
    out.sort((a, b) => coll.compare(a[sortBy], b[sortBy]) * (desc ? -1 : 1));
  }

  const pick = (r) => (keep ? keep.map((i) => r[i] ?? "") : r);
  return [pick(header), ...out.map(pick)];
}

const rows = [
  ["email", "name", "seats"],
  [" ada@example.com ", "Ada", "12"],
  ["grace@example.com", "Grace", "40"],
  ["", "", ""],
  ["ada@example.com", "Ada", "12"],
  ["bob@example.com", "Bob", "9"],
];
console.log(clean(rows, { sortBy: 2, desc: true, keep: [0, 2] }));

Intl.Collator with numeric: true sorts 9 before 10 and item2 before item10 without a separate number check.

Python

import csv

with open("users.csv", newline="", encoding="utf-8") as f:
    header, *rows = csv.reader(f)

rows = [[c.strip() for c in r] for r in rows]           # trim
rows = [r for r in rows if any(r)]                      # drop empty rows
rows = [r for r in rows if "free" not in r[2].lower()]  # filter on column 3

seen, unique = set(), []
for r in rows:                                          # dedupe on email
    if r[0] not in seen:
        seen.add(r[0])
        unique.append(r)

unique.sort(key=lambda r: float(r[3] or 0), reverse=True)  # numeric sort

keep = [0, 1, 3]                                        # email, name, seats
with open("clean.csv", "w", newline="", encoding="utf-8") as f:
    w = csv.writer(f)
    w.writerow([header[i] for i in keep])
    w.writerows([[r[i] for i in keep] for r in unique])

float(r[3] or 0) treats blank cells as 0; use a tuple key like (r[3] == "", float(r[3] or 0)) to push blanks to the end instead.

Common errors and how to fix them

Duplicates are not removed even though the rows look identical
The rows differ in whitespace or case. Keep Trim whitespace in cells on (it runs before deduplication). Case differences such as Bob and bob are treated as different values.
Sorting puts 100 before 20
The column contains something that is not a plain number, like a currency sign or unit, so it falls back to text order. Strip the symbol first, or sort in code with an explicit number conversion.
The column list shows Column 1, Column 2 instead of names
First row is header is unticked, or the delimiter is wrong and the whole header is one cell. Tick the header box and check the Detected delimiter above the input.
The header row got sorted into the data
First row is header was off, so the header was treated as a data row. Tick it and the first row stays on top.
Auto-detect picked the wrong delimiter
Unquoted text with many commas or semicolons can outnumber the real delimiter in the first lines. Pick the right one in the Delimiter menu; the Detected label above the input shows which one is in use.

Good to know

Steps run in a fixed order: trim, remove empty rows, filter, remove duplicates, sort, keep columns. Order matters for deduplication: with trimming on, " ada@example.com " and "ada@example.com" count as the same value. Sorting is stable, so rows with equal values keep their original order.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

How do I remove duplicate rows from a CSV file?

Paste or upload the CSV and keep Remove duplicate rows ticked. Choose By whole row to drop exact copies, or pick a key column such as email to keep only the first row for each value.

Can I sort a CSV by a numeric column?

Yes. Pick the column under Sort. Values that are numbers are compared as numbers, so 9 comes before 10, and blank cells always go last.

How do I delete columns from a CSV?

Untick the columns you do not want under Keep columns. The header and every row are cut down to the ticked columns, in their original order.

Does it change my data, like leading zeros or dates?

No. Apart from trimming whitespace when that step is on, values are copied through unchanged. Leading zeros, long IDs and date-like strings stay as text.

Is the CSV uploaded anywhere?

No. All the cleaning runs in your browser. Upload CSV reads the file locally, and nothing is sent to a server.

Why does my CSV use semicolons instead of commas?

Excel saves CSV with semicolons in locales where the comma is the decimal separator, such as Germany, France and the Netherlands, because 3,5 would otherwise split into two cells. Auto-detect normally spots this, and the Detected label above the input shows the choice. If it guesses wrong, pick Semicolon (;) in the Delimiter menu. The cleaned output keeps the semicolons so the same Excel opens it correctly.

Can I clean a pipe-delimited file?

Yes. Pick Pipe (|) under Delimiter, or leave Auto-detect on, which checks the first twenty lines for the character that appears the same number of times on each one. Pipes are common in database exports because addresses and names rarely contain them. Quoted fields are handled the same way as in a comma file, and the output is written with pipes again.

How do I sort a CSV alphabetically from A to Z?

Pick the column under 5. Sort and leave the direction at Ascending (A to Z, 1 to 9). Descending (Z to A, 9 to 1) flips the order. Letters compare case-insensitively, so apple and Banana sort as you would expect, and blank cells go last in both directions. The header stays on top as long as First row is header is ticked.

Once the rows are clean

Preview them in CSV to Table, load them with CSV to SQL or turn them into JSON. To change the delimiter, use the TSV to CSV Converter.

More Data Viewers

Browse all data viewers

Copied to clipboard!