Regex for Splitting CSV Strings — Handling Quoted Fields Correctly

line.split(',') is the first thing every developer tries on CSV data, and it works right up until a field contains a comma inside quotes — then every column after it shifts by one. This guide shows the regex fix, its limits, and when to reach for a real CSV parsing library instead.

The Problem with a Plain Comma Split

const row = 'John,"Doe, Jr.",Mumbai,India';

row.split(',');
// ['John', '"Doe', ' Jr."', 'Mumbai', 'India']
// WRONG — the quoted "Doe, Jr." field got split into two columns

Splitting with a Lookahead-Aware Regex

The trick is to only split on a comma when it is followed by an even number of quote characters for the rest of the line — meaning it is outside any open quote:

const row = 'John,"Doe, Jr.",Mumbai,India';

const fields = row.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);
console.log(fields);
// ['John', '"Doe, Jr."', 'Mumbai', 'India']  — correct!

// Strip the surrounding quotes afterward
const cleaned = fields.map((f) => f.replace(/^"|"$/g, ''));
// ['John', 'Doe, Jr.', 'Mumbai', 'India']

The lookahead (?=(?:(?:[^"]*"){2})*[^"]*$) counts quote characters ahead of each comma in pairs — if there's an even number of quotes remaining, the comma is "outside" a quoted field and safe to split on.

Extracting Fields Directly with a Match Regex

An alternative approach matches each field directly instead of splitting, which is often easier to reason about:

function parseCsvLine(line) {
  const fieldRegex = /(?:^|,)("(?:[^"]|"")*"|[^,]*)/g;
  const fields = [];
  let match;

  while ((match = fieldRegex.exec(line)) !== null) {
    if (match[0] === '' && match.index === line.length) break;
    let value = match[1];
    if (value.startsWith('"') && value.endsWith('"')) {
      value = value.slice(1, -1).replace(/""/g, '"'); // unescape doubled quotes
    }
    fields.push(value);
  }
  return fields;
}

parseCsvLine('John,"Doe, Jr.",Mumbai,"Says ""hi""!"');
// ['John', 'Doe, Jr.', 'Mumbai', 'Says "hi"!']

Where Regex-Based CSV Parsing Still Falls Short

  • Embedded newlines — a quoted field can legally contain a line break, which breaks any line-by-line regex approach that splits on \n first
  • Different encodings — UTF-8 BOM markers, non-UTF-8 files, and mixed line endings (CRLF vs LF) need dedicated handling
  • Alternate delimiters — semicolon-delimited "CSV" (common in European locales) or tab-delimited TSV need the pattern rewritten
  • Performance on large files — regex-per-line parsing of a multi-million-row file is far slower than a streaming parser built for the format

For any production import/export feature, use a library:

// Node.js — using csv-parse
const { parse } = require('csv-parse/sync');

const records = parse(csvString, {
  columns: true,
  skip_empty_lines: true,
});

When the Regex Approach Is Fine

  • You control the data source and know it never contains embedded newlines in fields
  • You are doing a quick one-off script or a small admin tool, not a production import pipeline
  • You need zero dependencies for a small serverless function with tight bundle size limits

Frequently Asked Questions

Why does string.split(",") break on CSV data?

Because CSV fields can contain commas inside quoted values, such as "Doe, John". A naive split(",") breaks that single field into two, misaligning every column after it.

What regex can split a CSV line while respecting quoted fields?

A common pattern is ,(?=(?:(?:[^"]*"){2})*[^"]*$), a comma split that uses a lookahead to only split on commas outside an even number of quotes, meaning commas inside quoted fields are preserved.

Should I use regex or a library to parse CSV files in production?

Use a dedicated library such as PapaParse (browser/Node.js) or csv-parse (Node.js) for production. They correctly handle escaped quotes, embedded newlines inside quoted fields, different delimiters, and encoding issues that a hand-written regex will not.

Try the Free AI Regex Generator

Describe any validation rule in plain English and get a working regex instantly — no signup required.

Related articles