26 KiB
Format String Syntax
The formatting functions in this library — most notably
fmt::format and fmt::print — accept
format strings written in the syntax described here.
A format string is plain text with embedded replacement fields delimited by
the braces { and }. Characters outside of any replacement field are
copied to the output unchanged. To emit a literal brace, double it: {{
yields a single { in the output, and }} yields a single }.
A replacement field is described by the grammar below.
replacement_field ::= "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
arg_id ::= integer | identifier
integer ::= digit+
digit ::= "0"..."9"
identifier ::= id_start id_continue*
id_start ::= "a"..."z" | "A"..."Z" | "_"
id_continue ::= id_start | digit
An arg_id selects which argument to format. It may be a non-negative
integer (positional reference) or an identifier matching the name of an
argument passed via fmt::arg (named reference). When arg_id
is omitted, arguments are consumed in left-to-right order; this automatic
indexing must be used uniformly throughout the format string — mixing
automatic and explicit numeric ids is a compile-time error (or a
format_error at runtime).
A format_spec, introduced by :, describes how the value should be
rendered. Its grammar is type-dependent; the form used by the standard
built-in types is documented in the next section.
For example:
fmt::format("hello, {}", "world");
// Result: "hello, world"
fmt::format("{1}, {0}!", "world", "hello");
// Result: "hello, world!"
fmt::format("{greeting}, {name}!",
fmt::arg("greeting", "hi"), fmt::arg("name", "fmt"));
// Result: "hi, fmt!"
A width or precision inside a format_spec may itself be written as a
nested replacement field — {} or {arg_id} — in which case it takes its
value from an integer argument at runtime. Nested fields accept only an
arg_id; they cannot themselves contain a format_spec.
Format Specification
The grammar below describes the format_spec shared by the built-in
types — integers, floating-point values, characters, strings, booleans, and
pointers — as well as by any user-defined type whose formatter reuses
fmt's parser.
format_spec ::= [[fill]align][sign]["#"]["0"][width]["." precision]["L"][type]
fill ::= <a character other than '{' or '}'>
align ::= "<" | ">" | "^"
sign ::= "+" | "-" | " "
width ::= integer | "{" [arg_id] "}"
precision ::= integer | "{" [arg_id] "}"
type ::= "a" | "A" | "b" | "B" | "c" | "d" | "e" | "E" | "f" | "F" |
"g" | "G" | "o" | "p" | "s" | "x" | "X" | "?"
Whether a particular option is meaningful depends on the value being
formatted; options that do not apply to a value's type are diagnosed at
compile time when possible and otherwise raise a format_error.
Fill and alignment
The align field selects where padding is placed when width makes the field wider than the value's natural rendering.
| Option | Effect |
|---|---|
< |
Left-align; pad on the right. Default for non-numeric types. |
> |
Right-align; pad on the left. Default for numeric types. |
^ |
Center the value; if the padding cannot be split evenly, the extra padding character goes on the right. |
The fill character is any single Unicode code point other than { or },
encoded the same way as the format string. It supplies the padding character
in place of the default space. A fill character is recognized only when it is
immediately followed by an align character — otherwise it would be
indistinguishable from an option in another position — so to use a custom
fill you must also specify an alignment.
Alignment has no observable effect when the value's natural rendering is already at least as wide as width; the value is never truncated to fit.
fmt::format("[{:<10}]", "42"); // Result: "[42 ]"
fmt::format("[{:>10}]", "42"); // Result: "[ 42]"
fmt::format("[{:^10}]", "42"); // Result: "[ 42 ]"
fmt::format("[{:*^10}]", "42"); // Result: "[****42****]" - '*' as fill
Sign
The sign field controls how the sign of a numeric value is emitted. It applies to signed integer and floating-point types only.
| Option | Effect |
|---|---|
+ |
Always emit a sign (+ for nonnegative values, - for negative). |
- |
Emit - only for negative values. This is the default. |
| space | Emit a leading space for nonnegative values and - for negative ones; useful for aligning columns of signed numbers. |
The sign of -0.0 is preserved in floating-point output.
fmt::format("{:+d} {:+d}", 7, -7); // Result: "+7 -7"
fmt::format("{: d} {: d}", 7, -7); // Result: " 7 -7"
Alternate form (#)
The # flag selects an alternate form whose exact meaning depends on the
presentation type:
- For integers rendered in binary, octal, or hexadecimal, it prepends the
appropriate base prefix (
0b/0B,0, or0x/0X). The case of the prefix follows the case of the type specifier —0xforx,0XforX, and so on. - For floating-point values, it forces the decimal point to appear in the
output even if no fractional digits would otherwise be emitted, and
prevents the
g/Gpresentation types from removing trailing zeros from the significand.
The # flag is not accepted by non-numeric types.
Zero padding (0)
A 0 placed immediately before width enables sign-aware zero padding for
numeric types. Zeros are inserted between the sign (or base prefix, if any)
and the most significant digit, so that a sign or 0x prefix stays adjacent
to the digits rather than being separated by spaces. For example, {:+08d}
applied to 120 produces +0000120.
Zero padding:
- applies only to numeric types;
- has no effect on
infornan; - is ignored when an explicit align is also present.
Width
width is a non-negative decimal integer giving the minimum number of characters that the field should occupy. If the formatted value is shorter than width, it is padded according to align and fill; if it is longer, the value is written in full. width never causes the value to be truncated.
To supply width at runtime, write the field as {} to consume the next
argument, or as {arg_id} to reference an integer argument by position or
by name.
When formatting strings, "width" is measured in display columns using a Unicode-aware estimate (East Asian wide and fullwidth characters, plus common emoji ranges, count as two columns; everything else counts as one). This keeps fixed width values visually consistent in monospace renderings that combine Latin and CJK text.
fmt::format("[{:6}]", 42);
// Result: "[ 42]" - right-aligned by default
fmt::format("[{:6}]", "hi");
// Result: "[hi ]" - left-aligned by default
fmt::format("[{:{}}]", 42, 6);
// Result: "[ 42]" - width from an argument
Precision
precision is a non-negative decimal integer (introduced by .) whose
meaning depends on the value being formatted. As with width, it may be
supplied as a nested replacement field for runtime evaluation.
| Type | Meaning of .precision |
|---|---|
e, E, f, F |
Digits emitted after the decimal point. |
g, G |
Total number of significant digits. |
a, A |
Digits after the decimal point in the hexadecimal significand. If omitted, just enough digits are emitted to round-trip the value exactly. |
Strings (s, ?, or default) |
Upper bound on the number of code points copied from the value. |
A precision is not accepted for integer, character, boolean, or pointer types. When a precision limits the number of characters taken from a C string, the string must still be null-terminated.
fmt::format("{:.2f}", 3.14159); // Result: "3.14"
fmt::format("{:.3g}", 3.14159); // Result: "3.14"
fmt::format("{:.4}", "hello, world"); // Result: "hell"
fmt::format("{:.{}f}", 3.14159, 4);
// Result: "3.1416" - precision from an argument
Locale (L)
The L flag selects locale-sensitive formatting for numeric types. The
formatter inspects the C++ locale supplied to the formatting function (or
the global locale, if none was passed) and inserts the locale's digit
grouping characters and — for floating-point values — its decimal point.
The flag has no effect on non-numeric types.
auto loc = std::locale("en_US.UTF-8");
fmt::format(loc, "{:L}", 1234567890); // Result: "1,234,567,890"
fmt::format(loc, "{:.2Lf}", 1234567.89); // Result: "1,234,567.89"
Presentation type
The type field chooses the representation for the value. Specifiers are grouped below by the value categories they apply to.
Integers, booleans, and characters:
| Type | Effect |
|---|---|
b |
Base 2. The # flag adds a 0b prefix. |
B |
Base 2. The # flag adds a 0B prefix. |
c |
Render the integer as the character with that code point. Not allowed for bool. |
d |
Base 10. The default for integer types. |
o |
Base 8. |
x |
Base 16, lower-case digits. The # flag adds a 0x prefix. |
X |
Base 16, upper-case digits. The # flag adds a 0X prefix. |
| none | Same as d for integers, c for characters, and the textual form (true/false) for bool. |
fmt::format("{:d} {:#x} {:#o} {:#b}", 42, 42, 42, 42);
// Result: "42 0x2a 052 0b101010"
fmt::format("{:#06x}", 0xfe); // # adds the prefix, 06 zero-pads to width 6
// Result: "0x00fe"
Floating-point values:
| Type | Effect |
|---|---|
a |
Hexadecimal-significand form (e.g. 1.8p+1). Lower-case digits and a lower-case p for the binary exponent. The # flag adds a 0x prefix. |
A |
Same as a, but upper-case throughout. |
e |
Scientific notation with a lower-case e for the decimal exponent. |
E |
Scientific notation with an upper-case E. |
f |
Fixed-point notation. |
F |
Same as f, but renders nan as NAN and inf as INF. |
g |
General form: scientific notation when the exponent would be less than −4 or not less than the precision, otherwise fixed-point; trailing zeros are removed from the fractional part unless # is set. A precision of 0 is interpreted as 1. |
G |
Same as g, but uses E for the exponent and upper-case INF/NAN. |
| none | Shortest round-trip representation: the formatted value, when parsed back into the same floating-point type, reproduces the input bit for bit. |
Strings and characters:
| Type | Effect |
|---|---|
s |
Plain string output. Default for string types and for bool (which is rendered as true or false). |
c |
Character output. Default for character types. Not allowed for bool. |
? |
Debug output: the value is wrapped in single quotes (characters) or double quotes (strings), and non-printable, non-ASCII, and special characters are escaped using C-style escape sequences such as \n, \t, \", and \u{...}. |
| none | Same as s for strings and bool, and as c for characters. |
fmt::format("{}", "tab\there"); // Result contains a literal tab character.
fmt::format("{:?}", "tab\there"); // Result: "\"tab\\there\""
Pointers:
| Type | Effect |
|---|---|
p |
Hexadecimal address prefixed by 0x. Default for pointer types. |
| none | Same as p. |
A C string (char* or const char*) accepts both the string presentation
types and p, so the same value can be formatted as either text or an
address.
Chrono Format Specification
The format specification for chrono duration and time point types as well
as std::tm has the following syntax:
chrono_format_spec ::= [[fill]align][width]["." precision][chrono_specs]
chrono_specs ::= conversion_spec |
chrono_specs (conversion_spec | literal_char)
conversion_spec ::= "%" [padding_modifier] [locale_modifier] chrono_type
literal_char ::= <a character other than '{', '}' or '%'>
padding_modifier ::= "-" | "_" | "0"
locale_modifier ::= "E" | "O"
chrono_type ::= "a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" |
"F" | "g" | "G" | "h" | "H" | "I" | "j" | "m" | "M" |
"n" | "p" | "q" | "Q" | "r" | "R" | "S" | "t" | "T" |
"u" | "U" | "V" | "w" | "W" | "x" | "X" | "y" | "Y" |
"z" | "Z" | "%"
Literal chars are copied unchanged to the output. Precision is valid only
for std::chrono::duration types with a floating-point representation type.
The available presentation types (chrono_type) are:
| Type | Meaning |
|---|---|
'a' |
The abbreviated weekday name, e.g. "Sat". If the value does not contain a
valid weekday, an exception of type format_error is thrown.
|
'A' |
The full weekday name, e.g. "Saturday". If the value does not contain a
valid weekday, an exception of type format_error is thrown.
|
'b' |
The abbreviated month name, e.g. "Nov". If the value does not contain a
valid month, an exception of type format_error is thrown.
|
'B' |
The full month name, e.g. "November". If the value does not contain a valid
month, an exception of type format_error is thrown.
|
'c' |
The date and time representation, e.g. "Sat Nov 12 22:04:00 1955". The
modified command %Ec produces the locale's alternate date and
time representation.
|
'C' |
The year divided by 100 using floored division, e.g. "19". If the result
is a single decimal digit, it is prefixed with 0. The modified command
%EC produces the locale's alternative representation of the
century.
|
'd' |
The day of month as a decimal number. If the result is a single decimal
digit, it is prefixed with 0. The modified command %Od
produces the locale's alternative representation.
|
'D' |
Equivalent to %m/%d/%y, e.g. "11/12/55". |
'e' |
The day of month as a decimal number. If the result is a single decimal
digit, it is prefixed with a space. The modified command %Oe
produces the locale's alternative representation.
|
'F' |
Equivalent to %Y-%m-%d, e.g. "1955-11-12". |
'g' |
The last two decimal digits of the ISO week-based year. If the result is a single digit it is prefixed by 0. |
'G' |
The ISO week-based year as a decimal number. If the result is less than four digits it is left-padded with 0 to four digits. |
'h' |
Equivalent to %b, e.g. "Nov". |
'H' |
The hour (24-hour clock) as a decimal number. If the result is a single
digit, it is prefixed with 0. The modified command %OH
produces the locale's alternative representation.
|
'I' |
The hour (12-hour clock) as a decimal number. If the result is a single
digit, it is prefixed with 0. The modified command %OI
produces the locale's alternative representation.
|
'j' |
If the type being formatted is a specialization of duration, the decimal number of days without padding. Otherwise, the day of the year as a decimal number. Jan 1 is 001. If the result is less than three digits, it is left-padded with 0 to three digits. |
'm' |
The month as a decimal number. Jan is 01. If the result is a single digit,
it is prefixed with 0. The modified command %Om produces the
locale's alternative representation.
|
'M' |
The minute as a decimal number. If the result is a single digit, it
is prefixed with 0. The modified command %OM produces the
locale's alternative representation.
|
'n' |
A new-line character. |
'p' |
The AM/PM designations associated with a 12-hour clock. |
'q' |
The duration's unit suffix. |
'Q' |
The duration's numeric value (as if extracted via .count()).
|
'r' |
The 12-hour clock time, e.g. "10:04:00 PM". |
'R' |
Equivalent to %H:%M, e.g. "22:04". |
'S' |
Seconds as a decimal number. If the number of seconds is less than 10, the
result is prefixed with 0. If the precision of the input cannot be exactly
represented with seconds, then the format is a decimal floating-point number
with a fixed format and a precision matching that of the precision of the
input (or to a microseconds precision if the conversion to floating-point
decimal seconds cannot be made within 18 fractional digits). The modified
command %OS produces the locale's alternative representation.
|
't' |
A horizontal-tab character. |
'T' |
Equivalent to %H:%M:%S. |
'u' |
The ISO weekday as a decimal number (1-7), where Monday is 1. The modified
command %Ou produces the locale's alternative representation.
|
'U' |
The week number of the year as a decimal number. The first Sunday of the
year is the first day of week 01. Days of the same year prior to that are
in week 00. If the result is a single digit, it is prefixed with 0.
The modified command %OU produces the locale's alternative
representation.
|
'V' |
The ISO week-based week number as a decimal number. If the result is a
single digit, it is prefixed with 0. The modified command %OV
produces the locale's alternative representation.
|
'w' |
The weekday as a decimal number (0-6), where Sunday is 0. The modified
command %Ow produces the locale's alternative representation.
|
'W' |
The week number of the year as a decimal number. The first Monday of the
year is the first day of week 01. Days of the same year prior to that are
in week 00. If the result is a single digit, it is prefixed with 0.
The modified command %OW produces the locale's alternative
representation.
|
'x' |
The date representation, e.g. "11/12/55". The modified command
%Ex produces the locale's alternate date representation.
|
'X' |
The time representation, e.g. "10:04:00". The modified command
%EX produces the locale's alternate time representation.
|
'y' |
The last two decimal digits of the year. If the result is a single digit
it is prefixed by 0. The modified command %Oy produces the
locale's alternative representation. The modified command %Ey
produces the locale's alternative representation of offset from
%EC (year only).
|
'Y' |
The year as a decimal number. If the result is less than four digits it is
left-padded with 0 to four digits. The modified command %EY
produces the locale's alternative full year representation.
|
'z' |
The offset from UTC in the ISO 8601:2004 format. For example -0430 refers
to 4 hours 30 minutes behind UTC. If the offset is zero, +0000 is used.
The modified commands %Ez and %Oz insert a
: between the hours and minutes: -04:30. If the offset
information is not available, an exception of type
format_error is thrown.
|
'Z' |
The time zone abbreviation. If the time zone abbreviation is not available,
an exception of type format_error is thrown.
|
'%' |
A % character. |
Specifiers that have a calendaric component such as 'd' (the day of month)
are valid only for std::tm and time points but not durations.
The available padding modifiers (padding_modifier) are:
| Type | Meaning |
|---|---|
'_' |
Pad a numeric result with spaces. |
'-' |
Do not pad a numeric result string. |
'0' |
Pad a numeric result string with zeros. |
These modifiers are only supported for the 'H', 'I', 'M', 'S', 'U',
'V', 'W', 'Y', 'd', 'j' and 'm' presentation types.
Example:
#include <fmt/chrono.h>
auto t = std::tm();
t.tm_year = 2010 - 1900;
t.tm_mon = 7;
t.tm_mday = 4;
t.tm_hour = 12;
t.tm_min = 15;
t.tm_sec = 58;
fmt::print("{:%Y-%m-%d %H:%M:%S}", t);
// Prints: 2010-08-04 12:15:58
Range Format Specification
The format specification for range types has the following syntax:
range_format_spec ::= ["n"][range_type][":" range_underlying_spec]
The 'n' option formats the range without the opening and closing brackets.
The available presentation types for range_type are:
| Type | Meaning |
|---|---|
| none | Default format. |
's' |
String format. The range is formatted as a string. |
'?s' |
Debug format. The range is formatted as an escaped string. |
If range_type is 's' or '?s', the range element type must be a character
type. The 'n' option and range_underlying_spec are mutually exclusive with
's' and '?s'.
The range_underlying_spec is parsed based on the formatter of the range's
element type.
By default, a range of characters or strings is printed escaped and quoted.
But if any range_underlying_spec is provided (even if it is empty), then the
characters or strings are printed according to the provided specification.
Examples:
fmt::print("{}", std::vector{10, 20, 30});
// Output: [10, 20, 30]
fmt::print("{::#x}", std::vector{10, 20, 30});
// Output: [0xa, 0x14, 0x1e]
fmt::print("{}", std::vector{'h', 'e', 'l', 'l', 'o'});
// Output: ['h', 'e', 'l', 'l', 'o']
fmt::print("{:n}", std::vector{'h', 'e', 'l', 'l', 'o'});
// Output: 'h', 'e', 'l', 'l', 'o'
fmt::print("{:s}", std::vector{'h', 'e', 'l', 'l', 'o'});
// Output: "hello"
fmt::print("{:?s}", std::vector{'h', 'e', 'l', 'l', 'o', '\n'});
// Output: "hello\n"
fmt::print("{::}", std::vector{'h', 'e', 'l', 'l', 'o'});
// Output: [h, e, l, l, o]
fmt::print("{::d}", std::vector{'h', 'e', 'l', 'l', 'o'});
// Output: [104, 101, 108, 108, 111]
fmt::print("{:n:f}", std::array{std::numbers::pi, std::numbers::e});
// Output: 3.141593, 2.718282
A Combined Example
The example below ties together several elements introduced above — nested replacement fields, fill characters, and centering — to draw a fixed-width box around a message:
fmt::print(
"┌{0:─^{2}}┐\n"
"│{1: ^{2}}│\n"
"└{0:─^{2}}┘\n", "", "Hello, world!", 20);
Output:
┌────────────────────┐
│ Hello, world! │
└────────────────────┘