Skip to content

JS engine's sniffDelimiter breaks on a quoted field containing a newline, unlike Python's csv.Sniffer #440

Description

@yakew7

Where: assets/profiler-engine.js's sniffDelimiter (splits raw text via .split(/\r\n|\r|\n/), not quote-aware) vs faircode/loaders.py's _sniff_delimiter (uses Python's csv.Sniffer, which is quote-aware).

The gap: for a delimited file with an unrecognized extension (so both engines take the sniffing code path - see the companion .csv-extension issue for the recognized-extension case), if one of the first sampled lines is a quoted field containing a literal newline, JS's naive line-split corrupts the sample: the embedded newline creates a spurious extra "line" mid-field, so the per-line delimiter counts stop being consistent and it falls back to the hardcoded default , - wrong. Python's csv.Sniffer still gets the real delimiter right on the identical file, since it understands quoting.

Repro: a file sniff_quoted_newline.dat (unrecognized extension), ;-delimited, with a quoted multi-line field in one row:

sex;race;age;notes
M;White;25;"single line"
F;Black;30;"multi
line note"
M;White;45;"ok"
F;Asian;22;"fine"
M;White;50;"good"
>>> from faircode.loaders import read_table
>>> read_table('sniff_quoted_newline.dat').shape
(5, 4)

Correct - 5 rows, 4 columns. Through the JS engine:

> E.sniffDelimiter(fs.readFileSync('sniff_quoted_newline.dat','utf8'))
','
> E.parseCSV(...).columns
[ 'sex;race;age;notes' ]

Sniffs the wrong delimiter and collapses into one garbage column.

Why it matters: same shared "sniff" logic, identical file, opposite outcomes - a real fairness dimension collapses into one bogus column in the browser tool while the CLI reads it correctly.

Suggested fix: make sniffDelimiter's line-sampling quote-aware - e.g. reuse parseCSV's own row-tokenizer to split rows before sampling for delimiter frequency, instead of a naive regex split on \n/\r.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions