Formatting Numbers
- Syntax
- Skeleton Stems and Options
Number skeletons are a locale-agnostic way to configure a NumberFormatter
in
ICU. Number skeletons work in MessageFormat
.
Syntax
- Number skeletons consist of case-sensitive token.
- Tokens are space-separated, with exceptions for concise skeletons listed at the end of this document.
- A token consists of a stem and zero or more options.
- The stem is what occurs before the first
/
character in a token. - Each option is preceeded by
/
.
sign-always compact-short currency/GBP
└─ stem ──┘ └── stem ───┘ └─stem─┘ └option┘
└─ token ─┘ └── token ──┘ └── token ─┘
// Language file
$txt['sample'] = 'You have {0, number, :: +! K currency/GBP} left.';
// Source code
\SMF\Lang::getTxt('sample', [45.18]);
- Output
- You have £45.18 left.
Skeleton Stems and Options
The full set of features supported by number skeletons is listed by category below.
Notation
Use one of the following stems to select compact or simple notation:
compact-short
orK
(concise)compact-long
orKK
(concise)notation-simple
(or omit since this is default)
There are two ways to select scientific or engineering notation: using long-form syntax or concise syntax.
Scientific and Engineering Notation: Long Form
Start with the stem scientific
or engineering
. Those stems take the following optional options:
/sign-xxx
sets the sign display option for the exponent; see Sign./*ee
sets exponent digits to “at least 2”; use/*eee
for at least 3 digits, etc.- Prior to ICU 67, use
/+ee
instead of/*ee
.
- Prior to ICU 67, use
For example, all the following skeletons are valid:
scientific
scientific/sign-always
scientific/*ee
scientific/*ee/sign-always
Scientific and Engineering Notation: Concise Form
The following are examples of concise form:
Concise Skeleton | Equivalent Long-Form Skeleton |
---|---|
E0 |
scientific |
E00 |
scientific/*ee |
EE+!0 |
engineering/sign-always |
E+?00 |
scientific/sign-except-zero/+ee |
More precisely:
- Start with
E
for scientific orEE
for engineering. - Allow either
+!
or+?
as a concise sign display option. - Expect one or more
0
s. If more than one, set minimum integer digits.
Unit
The supported types of units are percent, currency, and measurement units. The following skeleton tokens are accepted:
percent
or%
(concise)- Special:
%x100
to scale the number by 100 and then format with percent permille
base-unit
currency/XXX
measure-unit/aaaa-bbbb
orunit/bbb
(concise)
The percent
, permille
, and base-unit
stems do not take any options.
The currency
stem takes one required option: the three-letter ISO code of
the currency to be formatted.
The measure-unit
stem takes one required option: the unit identifier of the
unit to be formatted. The full unit identifier is required: both the type and
the subtype (for example, length-meter
).
The unit
stem is an alternative to measure-unit
that accepts a core unit
identifier with the subtype but not the type (for example, meter
instead of
length-meter
). It also supports variations allowed by UTS 35, including the per unit with the -per-
infix (for example, unit/furlong-per-second
).
Per Unit
To specify a unit to put in the denominator, use the following skeleton token.
As with the measure-unit
stem, pass the unit identifier as the option:
per-measure-unit/aaaa-bbbb
- Note
- If the
unit
stem is used, the denominator can be placed in the same token as the numerator.
Unit Width
The unit width can be specified by the following stems:
unit-width-narrow
unit-width-short
unit-width-full-name
unit-width-iso-code
unit-width-hidden
For more details, see
UNumberUnitWidth
.
Precision
The precision category has more blueprint stems than most other categories; they are documented in detail below. The following non-blueprint stems are accepted:
precision-integer
(round to the nearest integer) — accepts fraction-precision optionsprecision-unlimited
(do not perform rounding; display all digits)precision-increment/dddd
(round todddd
, a decimal number) — see belowprecision-currency-standard
precision-currency-cash
To round to the nearest nickel, for example, use the skeleton
precision-increment/0.05
. For more information on the decimal number
syntax, see Scale.
precision-increment/dddd
implies minimum and maximum fraction digits equal to the
precision of the decimal. There is not currently a way in skeleton syntax to specify
an arbitrary min/max fraction digits when a rounding increment is used.
All rounding occurs after the number is scaled, such as in scientific notation or
the scale
skeleton.
Fraction Precision
The following are examples of fraction-precision stems:
Stem | Explanation | Equivalent C++ Code |
---|---|---|
.00 |
Exactly 2 fraction digits | Precision::fixedFraction(2) |
.00* |
At least 2 fraction digits | Precision::minFraction(2) |
.## |
At most 2 fraction digits | Precision::maxFraction(2) |
.0# |
Between 1 and 2 fraction digits | Precision::minMaxFraction(1, 2) |
More precisely, the fraction precision stem starts with .
, then contains
zero or more 0
symbols, which implies the minimum fraction digits. Then it
contains either a *
, for unlimited maximum fraction digits, or zero or more
#
symbols, which implies the minimum fraction digits when added to the 0
symbols.
Note that the stem .
is considered valid and is equivalent to precision-integer
.
Fraction-precision stems accept a single optional option: a number of significant digits.
The options here correspond to the API functions on FractionPrecision
. Some options
require specifying r
or s
for relaxed mode or strict mode. For more information, see
the API docs for UNumberRoundingPriority.
Skeleton | Explanation | Equivalent C++ Code |
---|---|---|
.##/@@@* |
At most 2 fraction digits, but guarantee at least 3 significant digits |
Precision::maxFraction(2) .withMinDigits(3) |
.##/@##r |
Same as above | Precision::maxFraction(2) .withSignificantDigits(1, 3, RELAXED) |
.##/@@@r |
Same as above, but pad trailing zeros to at least 3 significant digits |
Precision::maxFraction(2) .withSignificantDigits(3, 3, RELAXED) |
.00/@## |
Exactly 2 fraction digits, but do not display more than 3 significant digits |
Precision::fixedFraction(2) .withMaxDigits(3) |
.00/@##s |
Same as above | Precision::fixedFraction(2) .withSignificantDigits(1, 3, STRICT) |
.00/@@@s |
Same as above, but pad trailing zeros to at least 3 significant digits |
Precision::fixedFraction(2) .withSignificantDigits(3, 3, STRICT) |
Precisely, the option follows the syntax of the significant digits stem (see below), but one of the following must be true:
- Option has one or more
@
s followed by the wildcard character (withMinDigits
) - Option has exactly one
@
followed by zero or more#
s (withMaxDigits
) - Option has one or more
@
s followed by zero or more#
s and ends ins
orr
(withSignificantDigits
)
Significant Digits Precision
The following are examples of stems for significant figures:
Stem | Explanation | Equivalent C++ Code |
---|---|---|
@@@ |
Exactly 3 significant digits | Precision::fixedSignificantDigits(3) |
@@@* |
At least 3 significant digits | Precision::minSignificantDigits(3) |
@## |
At most 3 significant digits | Precision::maxSignificantDigits(3) |
@@# |
Between 2 and 3 significant digits | ...::minMaxSignificantDigits(2, 3) |
The precise syntax is very similar to fraction precision. The blueprint stem
starts with one or more @
symbols, which implies the minimum significant
digits. Then it contains either a *
, for unlimited maximum significant
digits, or zero or more #
symbols, which implies the minimum significant
digits when added to the @
symbols.
Trailing Zero Display
Starting with ICU 69, a new option called trailingZeroDisplay
was added.
To enable this in an ICU number skeleton, append /w
to any precision token:
Skeleton | Explanation | Equivalent C++ Code |
---|---|---|
.00/w |
Exactly 2 fraction digits, but hide them if they are all 0 |
Precision::fixedFraction(2) .trailingZeroDisplay( UNUM_TRAILING_ZERO_HIDE_IF_WHOLE) |
precision-curren cy-standard/w |
Currency rounding, but hide fraction digits if they are all 0 |
Precision::currency(UCURR_USAGE_STANDARD) .trailingZeroDisplay( UNUM_TRAILING_ZERO_HIDE_IF_WHOLE) |
Wildcard Character
Prior to ICU 67, the symbol +
was used for unlimited precision, instead
of *
(for example, .00+
). For backwards compatibility, either +
or *
is
accepted. This applies for both fraction digits and significant digits.
Rounding Mode
The rounding mode can be specified by the following stems:
rounding-mode-ceiling
rounding-mode-floor
rounding-mode-down
rounding-mode-up
rounding-mode-half-even
rounding-mode-half-down
rounding-mode-half-up
rounding-mode-unnecessary
For more details, see Rounding Modes.
Integer Width
The following examples show how to specify integer width (minimum or maximum integer digits):
Long Form | Concise Form | Explanation | Equivalent C++ Code |
---|---|---|---|
integer-width/*000 |
000 |
At least 3 integer digits |
IntegerWidth::zeroFillTo(3) |
integer-width/##0 |
- | Between 1 and 3 integer digits |
IntegerWidth::zeroFillTo(1) .truncateAt(3) |
integer-width/00 |
- | Exactly 2 integer digits |
IntegerWidth::zeroFillTo(2) .truncateAt(2) |
integer-width/* |
- | Zero or more integer digits |
IntegerWidth::zeroFillTo(0) |
integer-width-trunc |
- | Zero integer digits | IntegerWidth::zeroFillTo(0) .truncateAt(0) |
The long-form option starts with either a single *
symbol, signaling no limit
on the number of integer digits (no truncateAt
), or zero or more #
symbols.
It should then be followed by zero or more 0
symbols, indicating the minimum
integer digits (the argument to zeroFillTo
). If there is no *
symbol, the
maximum integer digits (the argument to truncateAt
) is the number of #
symbols plus the number of 0
symbols.
The concise skeleton is simply one or more 0
characters. This supports
minimum integer digits but not maximum integer digits.
The special stem integer-width-trunc
covers the case when both truncateAt
and zeroFillTo
are zero.
Prior to ICU 67, use the symbol +
instead of *
.
Scale
To specify the scale, use the following stem and option:
scale/dddd
where dddd
is a decimal number. For example, the following are valid skeletons:
scale/100
(multiply by 100)scale/1E2
(same as above)scale/0.5
(multiply by 0.5)
The decimal number should conform to a standard decimal number syntax. In C++, it is parsed using the decimal number library described in LocalizedNumberFormatter::formatDecimal. In Java, it is parsed using BigDecimal. For maximum compatibility, it is highly recommended that your decimal number is able to be parsed by both engines.
Grouping
The grouping strategy can be specified by the following stems:
group-off
or,_
(concise)group-min2
or,?
(concise)group-auto
(or omit since this is the default)group-on-aligned
or,!
(concise)group-thousands
(no concise equivalent)
Symbols
The following stems are allowed for specifying the number symbols:
latin
(use Latin-script digits)numbering-system/nnnn
(use thennnn
numbering system)
Sign Display
The following stems specify sign display:
sign-auto
(or omit since this is the default)sign-always
or+!
(concise)sign-never
or+_
(concise)sign-accounting
or()
(concise)sign-accounting-always
or()!
(concise)sign-except-zero
or+?
(concise)sign-accounting-except-zero
or()?
(concise)sign-negative
or+-
(concise)sign-accounting-negative
or()-
(concise)
Decimal Separator Display
The following stems specify decimal separator display:
decimal-auto
decimal-always