Repository navigation
CSV import: From Text/CSV, sep=, apostrophes, quotes in Text to Columns and exponents match Excel - #965
Closed
iluebbe wants to merge 7 commits into
Closed
CSV import: From Text/CSV, sep=, apostrophes, quotes in Text to Columns and exponents match Excel#965iluebbe wants to merge 7 commits into
iluebbe wants to merge 7 commits into
Conversation
…e exponent The group check split the whole text at commas, so the exponent counted as a group: `1,5E3` (a decimal comma) was read as 15000 and `12,3e4` as 1230000, while `1,000E3` stayed text. Excel 365 reads `1,000E3` and `1,234E2` as numbers and keeps `1,5E3`, `-1,5E3`, `12,3e4` and `1,2e3` as text. The exponent is now split off before the thousands groups are checked. This affects typing, CSV import, Text to Columns and arithmetic on numeric text alike. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SAgnkqJiy3v24Hp25dQLRj
Fields went through the typing parser, where a leading apostrophe forces text and is dropped, so `'s-Hertogenbosch`, `'t Hooft`, `'93` and `'007` lost it on CSV open, From Text/CSV and Text to Columns. Excel 365 keeps the apostrophe in all three. Files and Text to Columns now use `parse_imported`, which keeps it; typing still forces text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SAgnkqJiy3v24Hp25dQLRj
… for CSV, paste and Text to Columns Text to Columns toggled quoting on every text qualifier, so `Pipe 12" long,5,EUR` stayed in one cell as `Pipe 12 long,5,EUR`, and `x "y, z" w` lost its quotes and its split. Excel 365 opens a quoted field only at the start of a field: `Pipe 12" long` | 5 | EUR, `x "y` | ` z" w`. CSV open, paste and Text to Columns had three copies of the same tokenizer that had drifted apart. They now share `split_records` / `split_fields` in the CSV module, with the delimiter set, text qualifier, "treat consecutive delimiters as one" and whether line breaks end a record as options. Doubled qualifiers inside a quoted field still read as one (storytold#119). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SAgnkqJiy3v24Hp25dQLRj
…p= and takes any delimiter character From Text/CSV only looked for a tab in the first line and otherwise split at commas, so a semicolon file (as a German Excel saves it) came in as one column per line, split again at its decimal commas (`1.234.567,89` → `1.234.567` and 89, `12,5 %` → 0.05). Without a `delimiter` it now uses the same detection as File › Open (`sniff_delimiter`, one copy). Both now honour Excel's `sep=X` first line: they split on X and don't import the line, so `sep=|` files open in columns. A given delimiter wins, and the line stays data. The delimiter option is a character instead of a byte: `;` (U+FF1B) splits, and a character whose low byte is a comma no longer splits at commas. A `delimiter` param that isn't one character is refused instead of using its first letter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SAgnkqJiy3v24Hp25dQLRj
…as, number formats kept
From Text/CSV turned every value into JSON and wrote it back with `range.setValues`,
which treats strings as typed input. A field `=1+1` became a formula and
`=HYPERLINK("http://example.com","click")` a working link (a CSV injection path that
File › Open and Excel's From Text/CSV don't have). Numbers lost their formats on the
way, so `2024-03-04` showed as 45355, `12.5%` as 0.125 and `$1,234.50` as 1234.5.
It now writes the cells `read_csv` produced, with their number formats, so it types
fields exactly as File › Open does. JSON strings from Get Data are read the same way.
Both use the workbook's date system instead of always 1900.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAgnkqJiy3v24Hp25dQLRj
Any text starting with `[` was parsed as JSON, so a CSV with a header like `[ID],Name` failed with "invalid parameters for `data.getData`: expected value at line 1 column 2" (File › Open reads it). The text is now JSON only when it parses as a JSON array of objects, or when the file is a `.json`; otherwise it's read as CSV. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SAgnkqJiy3v24Hp25dQLRj
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SAgnkqJiy3v24Hp25dQLRj
Author
|
Closing this pull request. The problem, Excel's measurements and a fix approach are now in #1446. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
I tested CSV and text import against Excel 365 on Windows (de-DE UI). The test covered File › Open, Data › From Text/CSV (
data.fromTextCsv), paste with Text to Columns, and NUMBERVALUE / TEXTSPLIT. It used about 60 variant files: delimiters,;TAB|, quoting, line ends, BOMs, en-US / de-DE / fr / de-CH / en-IN / zh-CN numbers and dates, and Windows-1252 / UTF-16 / GB18030. Nine bugs came up. Main84acf62is the baseline; I found no existing issue or PR for any of them.;-separated file (r2;1.234.567,89,12,5 %);(File › Open in GridCraft does too)1.234.567,89→"r2;1.234.567"and 89,12,5 %→ 0.05)=1+1,=HYPERLINK("http://example.com","click")2and a working hyperlink; an unquoted comma inside the formula splits it2024-03-04,12.5%,$1,234.5045355,0.125,1234.5(General)[ID],Namedata.getData: expected value at line 1 column 2" (read as JSON)'s-Hertogenbosch,'t Hooft,'007s-Hertogenbosch,007)Pipe 12" long,5,EUR;5'10" tall,180,cmPipe 12" long| 5 | EUR;5'10" tall| 180 | cmPipe 12 long,5,EUR; one cell5'10 tall,180,cm(a quote anywhere toggles quoting)sep=|(orsep=;,sep=,)sep=row; a pipe file stays one column1,5E3,-1,5E3,12,3e4,1,2e31,5E3, meaning 1500, becomes 15000)1,000E3,1,234E2delimiter: ";"(U+FF1B)as u8, so it never splits; a character whose low byte is 0x2C would split at commasCause
crates/engine/src/cmd/extra.rs):sniff_delimiter.as u8.[as JSON.range.setValues, which parses each field as typed input, so formulas went live and number formats were lost.parse_input(crates/core/src/parse.rs), where a leading'is the typed-text prefix.split_delimited(crates/engine/src/cmd/data.rs) was a third tokenizer, next tocsv.rs(File › Open) andparse_tsv(paste). It toggled quoting on any"and dropped the quote.parse_plainchecked digit groups on the whole number including the exponent, so5E3counted as a group of three.Fix
parse_tsv) and Text to Columns now share one tokenizer incrates/xlsx/src/csv.rs(split_records/split_fieldswith aDelimitedoptions struct). The copies indata.rsandedit.rsare gone.delimiterit detects the delimiter as File › Open does.sep=Xfirst line (when the delimiter is detected) and hide it.CsvOptions.delimiteris achar('\0'means detect), so any character works; adelimiterparam longer than one character is refused.read_csvproduced, values with their number formats, never through typing. JSON strings are read like CSV fields. Both use the workbook's date system..json.parse_importedin core keeps a leading apostrophe as text. Typing'abcstill forces text.parse_plainchecks thousands groups on the mantissa only.docs/file-format-parity.md: CSV rows and a revision row.Not changed here:
0,001→ 1,04.03.2024→ 3 April. Those belong to the regional-format work in M12: Excel-style languages (12 languages, local formulas, regional formats) #191, M12: regional formats (typed and displayed numbers, dates and times) #447 and Data: Automatic Data Conversion options for typing, pasting and opening CSV (#506) #583.=1+1in File › Open: it stays text. Excel's double-click open makes a formula, but keeping text looks deliberate (safety), so I left it as is.|is not added to automatic detection. Excel's File › Open doesn't split on pipes either;sep=|covers those files.Testing
New tests:
thousands_separators_belong_to_the_mantissa, plus apostrophe cases forparse_imported.a_quote_inside_a_field_is_a_character,a_sep_line_names_the_delimiter,any_character_can_be_the_delimiter, plus apostrophe cases.text_to_columns_keeps_a_leading_apostrophe,text_to_columns_reads_a_quote_inside_a_field_as_a_character,from_text_csv_detects_the_delimiter_like_file_open,from_text_csv_keeps_field_text_and_number_formats,from_text_csv_reads_a_bracketed_header_as_csv.cargo xtask ci: fmt, clippy, test, assets, layers and wasm pass.parityandkeytips --checkdiffer only in line endings on this Windows checkout (core.autocrlf); main does the same here.Re-run of the Excel comparison: cells that differ from Excel 365, main → this branch. No count went up anywhere.
sep=,/sep=;/sep=|sep=,/sep=;/sep=|;, de-DE, cp1252, de-CH, fr filesThe remaining differences are the locale options above.
Overlaps:
parse_plainincrates/core/src/parse.rs. This change is limited to the group check.csv.rs;CsvOptions.delimiteris now achar.🤖 Generated with Claude Code
https://claude.ai/code/session_01SAgnkqJiy3v24Hp25dQLRj