Summary
Add a public expl3 function that parses a quantity (number + unit) through the normal siunitx pipeline — including prefix extraction, rounding, scientific/engineering exponent handling, and the extract-exponent / extract-mass-in-kilograms rules — but instead of typesetting the result, returns the decomposed components (sign, mantissa, exponent, extracted prefix, base unit, …) as an expl3 property list. This lets downstream code consume any subset of the parsed data, without re-implementing siunitx's parsing rules.
Motivation
siunitx currently offers a rich key–value interface for how a quantity is typeset, but treats the parsed decomposition as an implementation detail. Several common use-cases need access to the individual fields:
- Plot axis labels. When an axis is scaled by a power of ten, the author wants to put that same exponent (combined with any prefix extracted from the unit) in the label, while the tick labels show the unscaled numbers. Today this requires either double bookkeeping (letting siunitx format the label and separately teaching pgfplots about the exponent) or hand-rolled prefix arithmetic. A call that returns "after prefix extraction, exponent is 3 and the base unit is
\metre" solves this cleanly.
- Table alignment on the mantissa. Aligning a column on the decimal marker of the mantissa regardless of how the exponent is rendered currently relies on
table-* keys. Direct access to mantissa-int / mantissa-dec / exponent would let authors build their own alignment, including in non-table contexts (aligned equations, matrices).
- Calculations with parsed values. Packages that combine siunitx input with
\fpeval/\int_eval typically re-parse the number themselves. Exposing the already-parsed numeric fields removes that duplication and guarantees consistent rules.
- Conditional formatting. "Print the bare unit if mantissa = 1 and exponent = 0 after extraction, otherwise print the full quantity" is a recurring pattern (see §Concrete case below). A public parser makes this a two-line conditional instead of an internal-function override.
Concrete case (illustrative)
Pgfplots axis label with prefix-mode = extract-exponent, extract-mass-in-kilograms = true, input \qty{1e-3}{\km}:
- Desired output when the net result reduces to mantissa 1 and exponent 0: just the base unit (e.g.
m), no "1", no "10^0", no thin-space.
- Current behaviour:
print-unity-mantissa = false + print-zero-exponent = false still print 1 as a fallback (see \__siunitx_number_output_integer:nnn, siunitx.sty, around line 2319), because at that layer siunitx doesn't know there is still a unit to anchor the output.
A documented parser would allow:
\siunitx_quantity_parse:nnnN
{ prefix-mode = extract-exponent, extract-mass-in-kilograms = true }
{ 1e-3 } { \km } \l_tmpa_prop
\prop_get:NnN \l_tmpa_prop { mantissa-int } \l_tmpa_tl % "1"
\prop_get:NnN \l_tmpa_prop { exponent } \l_tmpb_tl % "0"
\prop_get:NnN \l_tmpa_prop { unit } \l_tmpc_tl % "\metre"
% ... then decide locally how to typeset.
Feasibility
The decomposition already exists internally. \__siunitx_number_output:nnnnnnn (siunitx.sty, line 2235) receives seven separate fields — sign, color, integer, decimal, uncertainty, exponent, trailing — and calls field-specific output routines (\__siunitx_number_output_integer:nnn, …_decimal:nn, …_exponent:nnnnn, …_end:). Prefix extraction has likewise already run by the time these are called.
siunitx also already publishes a small expl3 layer that follows naming conventions consistent with this proposal:
\siunitx_if_number:n[TF] (siunitx.sty, line 2803)
\siunitx_number_parse:nN
\siunitx_number_output:N, \siunitx_number_output:n (lines 2215–2219)
\siunitx_quantity_product:nn (line 4798)
\siunitx_quantity_print:nn (line 8005 region)
So the request is not a new architecture — it is exposing data that the pipeline already has, through a function that matches the existing naming scheme.
Proposed API
\siunitx_quantity_parse:nnnN { <options> } { <number> } { <unit> } <prop var>
Runs the full siunitx parsing pipeline (including prefix-mode,
rounding, uncertainty, scientific / engineering / fixed
exponent handling, extract-mass-in-kilograms, …) with the
given options applied locally. Stores the parsed fields as
entries in <prop var>. Does not typeset anything.
Keys stored in <prop var>:
sign "+" | "-" | ""
mantissa-int integer part of the mantissa, e.g. "1", "", "0"
mantissa-dec decimal part of the mantissa, e.g. "25", ""
uncertainty uncertainty token list (format as siunitx emits)
exponent final exponent after prefix extraction, e.g. "3", "0", ""
prefix prefix token extracted from the unit, e.g. "\kilo", ""
unit base unit after prefix extraction, e.g. "\metre"
unit-raw the unit as written by the user (pre-extraction)
Variant: ...parse:nnnNTF that also branches on "is this a valid
quantity".
Companion public-layer additions that would round out the API:
\siunitx_quantity_typeset:N <prop var> — typeset from a property list produced by parse:nnnN. Lets the caller mutate fields between parse and typeset (e.g. force a specific exponent, swap a unit).
- A
quantity-hook key whose value is a callback \cs { ... } receiving the property list, invoked at the point in \qty/\SI where typesetting would begin. Same data path as parse:nnnN, but plugged into the existing user-level macros, so existing \qty[...]{}{} call sites can opt in.
Backwards compatibility
Pure addition. No existing key, macro, or internal function changes semantics; \qty, \num, \SI, \ang, the S column type all behave identically for users who do not call the new functions or set the new key.
Documentation placement
- User-facing mention in
siunitx.pdf under a new "Accessing parsed quantities" section, alongside the existing expl3 API listing.
- Full signatures in
siunitx-code.pdf, consistent with how \siunitx_number_parse:nN and \siunitx_quantity_product:nn are already documented there.
Closing
The change is a modest, additive exposure of data the package already computes. It would remove a recurring class of workaround — reparsing in user code, or overriding internal \__siunitx_* functions — and fits naturally into siunitx's existing expl3 public layer.
Summary
Add a public expl3 function that parses a quantity (number + unit) through the normal siunitx pipeline — including prefix extraction, rounding, scientific/engineering exponent handling, and the
extract-exponent/extract-mass-in-kilogramsrules — but instead of typesetting the result, returns the decomposed components (sign, mantissa, exponent, extracted prefix, base unit, …) as an expl3 property list. This lets downstream code consume any subset of the parsed data, without re-implementing siunitx's parsing rules.Motivation
siunitx currently offers a rich key–value interface for how a quantity is typeset, but treats the parsed decomposition as an implementation detail. Several common use-cases need access to the individual fields:
\metre" solves this cleanly.table-*keys. Direct access tomantissa-int/mantissa-dec/exponentwould let authors build their own alignment, including in non-table contexts (aligned equations, matrices).\fpeval/\int_evaltypically re-parse the number themselves. Exposing the already-parsed numeric fields removes that duplication and guarantees consistent rules.Concrete case (illustrative)
Pgfplots axis label with
prefix-mode = extract-exponent, extract-mass-in-kilograms = true, input\qty{1e-3}{\km}:m), no "1", no "10^0", no thin-space.print-unity-mantissa = false+print-zero-exponent = falsestill print1as a fallback (see\__siunitx_number_output_integer:nnn,siunitx.sty, around line 2319), because at that layer siunitx doesn't know there is still a unit to anchor the output.A documented parser would allow:
Feasibility
The decomposition already exists internally.
\__siunitx_number_output:nnnnnnn(siunitx.sty, line 2235) receives seven separate fields — sign, color, integer, decimal, uncertainty, exponent, trailing — and calls field-specific output routines (\__siunitx_number_output_integer:nnn,…_decimal:nn,…_exponent:nnnnn,…_end:). Prefix extraction has likewise already run by the time these are called.siunitx also already publishes a small expl3 layer that follows naming conventions consistent with this proposal:
\siunitx_if_number:n[TF](siunitx.sty, line 2803)\siunitx_number_parse:nN\siunitx_number_output:N,\siunitx_number_output:n(lines 2215–2219)\siunitx_quantity_product:nn(line 4798)\siunitx_quantity_print:nn(line 8005 region)So the request is not a new architecture — it is exposing data that the pipeline already has, through a function that matches the existing naming scheme.
Proposed API
Companion public-layer additions that would round out the API:
\siunitx_quantity_typeset:N <prop var>— typeset from a property list produced byparse:nnnN. Lets the caller mutate fields between parse and typeset (e.g. force a specific exponent, swap a unit).quantity-hookkey whose value is a callback\cs { ... }receiving the property list, invoked at the point in\qty/\SIwhere typesetting would begin. Same data path asparse:nnnN, but plugged into the existing user-level macros, so existing\qty[...]{}{}call sites can opt in.Backwards compatibility
Pure addition. No existing key, macro, or internal function changes semantics;
\qty,\num,\SI,\ang, theScolumn type all behave identically for users who do not call the new functions or set the new key.Documentation placement
siunitx.pdfunder a new "Accessing parsed quantities" section, alongside the existing expl3 API listing.siunitx-code.pdf, consistent with how\siunitx_number_parse:nNand\siunitx_quantity_product:nnare already documented there.Closing
The change is a modest, additive exposure of data the package already computes. It would remove a recurring class of workaround — reparsing in user code, or overriding internal
\__siunitx_*functions — and fits naturally into siunitx's existing expl3 public layer.