Consider this small delimited file:

id,name;label 1,A;B 

With a comma delimiter, it has two columns:

[ ["id", "name;label"], ["1", "A;B"] ] 

With a semicolon delimiter, it also has two columns:

[ ["id,name", "label"], ["1,A", "B"] ] 

Both interpretations have consistent row widths. Choosing whichever delimiter appears first in a candidate list hides an unresolved decision.

Separate parsing from selection

Parse each candidate using a parser configured for that delimiter. A candidate is usable only if it passes the syntax and table-shape checks your importer requires.

Those checks should include quoted fields, escaped quotes, embedded newlines, and a consistent number of fields per record. Counting punctuation or splitting the first line cannot handle all of them.

RFC 4180 describes the comma-separated format and its quoting rules. Semicolon-separated files are a separate dialect that an importer may deliberately support; the RFC does not define automatic delimiter detection.

The selection step can then work with small summaries. Here is one explicit heuristic: prefer the unique valid candidate with the most columns, and otherwise ask for a choice.

function chooseDelimiter(candidates) { const usable = candidates.filter(c => c.valid && c.columns > 1); if (usable.length === 0) { return { status: "needs-choice", reason: "no-multicolumn-candidate" }; } const width = Math.max(...usable.map(c => c.columns)); const leaders = usable.filter(c => c.columns === width); if (leaders.length !== 1) { return { status: "needs-choice", reason: "ambiguous", delimiters: leaders.map(c => c.delimiter) }; } return { status: "suggested", delimiter: leaders[0].delimiter }; } console.log(chooseDelimiter([ { delimiter: ",", valid: true, columns: 2 }, { delimiter: ";", valid: true, columns: 2 }, { delimiter: "\t", valid: true, columns: 1 } ])); // { status: "needs-choice", reason: "ambiguous", delimiters: [",", ";"] } 

This function selects among parser results. It does not parse CSV, and valid must come from the parser and validation step, not from a delimiter count.

A suggestion still needs a preview

The widest candidate is a heuristic, not proof. Punctuation inside unquoted values can make the wrong dialect look plausible. A known export format or an expected header schema is stronger evidence.

Also, one-column CSV is valid. The columns > 1 filter means that this heuristic cannot infer a useful delimiter from it; it does not mean the file should be rejected.

Offer comma, semicolon, and tab as explicit choices when those are the dialects your importer supports. Reparse the original text after a choice, show the resulting headers and sample rows, and keep existing imported data until confirmation.

Representing ambiguity as a normal result gives the interface something useful to do before a mistaken guess changes stored data.

Follow this DEV profile for more practical examples of reliable JavaScript import workflows.