Format and parse metric numerals
Orientation
Use ToMetric for compact decimal magnitudes such as 123.5k, and
FromMetric when an input follows Humanizer’s metric syntax.
MetricNumeralFormats selects a symbol, SI prefix name, scale word, and
optional spacing. Humanizer 4 can also preserve a fixed number of fractional
digits. Numeric text follows CurrentCulture; automatic scale-word selection
follows CurrentUICulture and reuses that locale's number-word data.
Example
The example pins en-US for numbers and de-DE for UI language, controls
decimals, preserves a fixed decimal width, automatically selects a scale word,
emits an SI prefix name, and parses a symbol:
using System.Globalization;
using Humanizer;
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("de-DE");
var symbol = 123_456.ToMetric(decimals: 1);
var fixedWidth = 1_000d.ToMetric(
MetricNumeralFormats.KeepTrailingZeros,
decimals: 2);
var name = 1_000d.ToMetric(
MetricNumeralFormats.WithSpace | MetricNumeralFormats.UseName);
var scaleWord = 1.5E9.ToMetric(
MetricNumeralFormats.KeepTrailingZeros |
MetricNumeralFormats.WithSpace |
MetricNumeralFormats.UseScaleWord,
decimals: 2);
var parsed = "1.5k".FromMetric();
AssertEqual("123.5k", symbol);
AssertEqual("1.00k", fixedWidth);
AssertEqual("1 kilo", name);
AssertEqual("1.50 Milliarden", scaleWord);
AssertEqual(1500d, parsed);
Console.WriteLine($"{symbol}; {fixedWidth}; {name}; {scaleWord}; {parsed}");
static void AssertEqual<T>(T expected, T actual)
{
if (!EqualityComparer<T>.Default.Equals(expected, actual))
throw new InvalidOperationException($"Expected '{expected}', got '{actual}'.");
}
Select the representation
MetricNumeralFormats is a flags enum:
WithSpaceinserts a space before the suffix.UseNameemits an SI prefix name such askilo.UseShortScaleWordemits words such asbillion.UseLongScaleWordemits the selected long-scale equivalent.UseScaleWordemits the exact scale term authored forCurrentUICulture. It selects the locale-authored grammatical count form from the displayed, scaled numeral. Inverse scale words are used only for an authored singular form; other inverse counts keep the invariant SI symbol. When the locale has no standalone term for that power of 1000, it keeps the invariant SI symbol instead of falling back to an English word.KeepTrailingZerosincludes exactly the number of fractional digits requested bydecimals.
Without KeepTrailingZeros, the nullable decimals argument is the maximum
number of fractional digits: rounding applies at that limit and trailing zeros
are omitted. Combine KeepTrailingZeros with a non-null decimals value when
fixed-width output matters. The flag has no effect when decimals is null.
It also applies to zero, negative values, values without a metric prefix, and
values rounded into the next prefix. Leave both options unset to preserve the
available precision in the default representation.
Use UseScaleWord for user-facing output that should follow the UI locale.
Use UseShortScaleWord or UseLongScaleWord when an external format requires
the existing English short- or long-scale vocabulary regardless of locale.
CurrentCulture still controls the decimal separator and other numeric
formatting in either case. KeepTrailingZeros composes with those
representations and with WithSpace. When
KeepTrailingZeros is active with a non-null decimals value, WithSpace
still emits its trailing space even when no suffix is present, including for
zero.
Parse supported forms
FromMetric accepts a numeric value followed by a supported SI symbol or prefix name, with optional whitespace. It returns double and throws ArgumentException for invalid syntax. Short- and long-scale words produced by ToMetric are display forms and do not round-trip through FromMetric.
Pitfall
Metric prefixes are powers of 1000. ByteSize uses a mixed unit contract:
legacy KB through TB are binary multiples, PB and EB are decimal SI,
and explicit IEC symbols such as KiB and PiB are binary. The supported
metric exponent range stops before 10^27 and below 10^-27; out-of-range
values throw. Because there is no culture parameter, scope CurrentCulture
when parsing or exact numeric output matters, and scope CurrentUICulture
when UseScaleWord must be deterministic.
Version notes
Metric conversion spans the documented corpus, but Humanizer 3 removed older
boolean formatting overloads in favor of MetricNumeralFormats.
UseScaleWord and KeepTrailingZeros are available in Humanizer 4. The
executable uses the selected version's formatting API and runs against that
package.