Skip to content

JS engine's parseCSV strips quote characters mid-field, diverging from pandas' quoting semantics #441

Description

@yakew7

Where: assets/profiler-engine.js's parseCSV char-loop (else if (c === '"') { inQuotes = true; } fires on any " encountered while accumulating a field, regardless of position) vs pandas' C parser, which only treats a quote as significant when it's the very first character of a field.

The gap: a common "space after delimiter" export style (Male, "White", 25) has a leading space before the quote in each quoted field. Pandas' parser (no skipinitialspace) sees the leading space as real field content, so the quote isn't at the true start of the field and is preserved literally. The JS engine's state machine doesn't check position - any " flips inQuotes on - so it silently strips the quote characters, changing the parsed value.

Repro: a file space_before_quote.csv:

sex, race, age
Male, "White", 25
Female, "Black", 30
Male, "White", 45
Female, "Asian", 22
>>> import pandas as pd
>>> from faircode import profile
>>> df = pd.read_csv('space_before_quote.csv')
>>> [g['label'] for g in profile(df)['dimensions'][0]['groups']]
[' "White"', ' "Asian"', ' "Black"']

Through the JS engine on the identical file:

> E.profile(E.parseCSV(fs.readFileSync('space_before_quote.csv','utf8'))).dimensions
  .find(d => d.name === ' race').groups.map(g => g.label)
[ ' White', ' Asian', ' Black' ]

Both engines "succeed" - neither errors - but disagree on what the group label literally is (quotes present vs stripped).

Why it matters: this isn't a parse error on either side, so nothing surfaces it - it's a silent divergence in what a protected group's label is. Any downstream consumer that matches labels exactly (a --reference baseline, a --map override, a saved comparison) would silently disagree between the CLI and the web profiler on an ordinary Excel-exported CSV with this common export style.

Suggested fix: only enter quote mode when " is the very first character accumulated for the current field (mirror pandas: only when the field buffer is still empty and no non-quote character has been seen yet), so a quote appearing after other content is treated as a literal character.

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