Skip to content

feat(number_format): parse a format code and format a number with it - #970

Merged
andiwand merged 2 commits into
mainfrom
feat/number-format-numbers
Oct 4, 2026
Merged

andiwand merged 2 commits into
mainfrom
feat/number-format-numbers

Conversation

@andiwand

@andiwand andiwand commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Step 1 of the number-format plan (decision 14).

Change

New src/odr/internal/number_format/: Format parses a format code, and Format::format turns a number or a text into the text a cell shows. No reader uses it yet.

  • Grammar: MS-XLS 2.4.126, the ABNF in offline/documentation.
    • Up to four sections, split on ; outside quotes and brackets.
    • [>=1000] conditions; [$€-407] shows its symbol; a colour and [DBNum1] change nothing.
    • 0, #, ?, the point, %, E+/E-, / fractions, @ and General.
    • Literals: "…", \x, _x as a space, and *x as nothing, because a fill needs the cell width.
  • Commas: a comma between integer placeholders groups the integer. A comma after the last placeholder divides by a thousand. Any other comma is a literal.
  • Sections: one section for all numbers. Two: non-negative, then negative without its minus. Three: positive, negative, zero. The fourth takes text. With a condition, the first section that matches wins. A section for the negative values drops the sign. A value that rounds to all zeros shows no minus.
  • Rounding: half away from zero, on the 15-digit decimal spelling. So 2.675 with 0.00 shows 2.68, as a spreadsheet does, not 2.67.
  • Integer placeholders: they fill right to left, and the leftmost takes the extra digits. So 000-00-0000 works.
  • Scientific notation: ##0.0E+0 steps the exponent by three.
  • Fractions: the best denominator within the placeholder digits, or a fixed one such as ?/8.
  • General: 15 significant digits, and scientific notation outside [1e-10, 1e15). So 0.1+0.2 shows 0.3.
  • Dates and times: a token is refused with std::invalid_argument until the next step.

Review after the rebase

  • An infinity or a NaN threw out of std::stoi, because fmt spells it without an exponent; it shows as fmt spells it now.
  • A mantissa of an engineering format that rounds into the next power stayed on the old one: 999.99 with ##0.0E+0 showed 1000.0E+0, now 1.0E+3.
  • Format::sections had no caller and goes.

Both new test cases fail on the old code.

Proof

  • NumberFormat.*: 11 tests, 0 failed, with the two cases of the review. They cover each rule above, with the cases the spreadsheets themselves show.
  • Homebrew clang and g++-15 with -Wall -Wextra -Werror are clean on both new files. The run caught a missing designated initializer, which the type now defaults, and a trigraph in a test string.
  • clang-tidy is clean on number_format.cpp.

Base automatically changed from docs/plan-number-formats to main October 4, 2026 10:16
andiwand and others added 2 commits October 4, 2026 12:18
`internal/number_format` parses a format code as MS-XLS 2.4.126 states its
grammar: up to four sections, a condition, `0`, `#`, `?`, the point, commas
that group or scale, `%`, `E+` and `E-`, fractions, `@`, `General`, and
quoted, escaped, `_` and `*` literals. `Format::format` picks the section by
sign or condition and rounds half away from zero on the 15-digit spelling.
A date or time token is refused until the next step.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011qFgpigFCwbfZ24TFj7eqA
…g mantissa

An infinity or a NaN threw out of `std::stoi`, because fmt spells it without
an exponent; it shows as fmt spells it now. A mantissa of an engineering
format (`##0.0E+0`) that rounds into the next power stayed on the old one,
so 999.99 showed `1000.0E+0`; it moves by the step now and shows `1.0E+3`.
`Format::sections` had no caller and goes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011qFgpigFCwbfZ24TFj7eqA
@andiwand
andiwand force-pushed the feat/number-format-numbers branch from 18f23c6 to 387580d Compare October 4, 2026 10:19
@andiwand
andiwand merged commit dde382e into main Oct 4, 2026
22 of 23 checks passed
@andiwand
andiwand deleted the feat/number-format-numbers branch October 4, 2026 10:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant