Skip to content

Rust format specifier grammar

When several formatting controls appear in one field, their order is fixed. Rust’s standard grammar is the authoritative answer.

format_string := text [ maybe_format text ] *
maybe_format := '{' '{' | '}' '}' | format
format := '{' [ argument ] [ ':' format_spec ] [ ws ] * '}'
argument := integer | identifier
format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
fill := character
align := '<' | '^' | '>'
sign := '+' | '-'
width := count
precision := count | '*'
type := '?' | 'x?' | 'X?' | 'o' | 'x' | 'X' | 'p' | 'b' | 'e' | 'E'
count := parameter | integer
parameter := argument '$'

Consider {value:#010x}. value selects the argument, : starts the format specification, # requests the alternate hexadecimal form, 0 enables sign-aware numeric zero padding, 10 is the minimum width, and x selects LowerHex.

EXAMPLE: CI-CHECKEDTEST ASSERTED · examples/format-output/src/format_pages.rs#format-grammar-walkthrough
let value = 27;
assert_eq!(format!("{value:#010x}"), "0x0000001b");

The resulting width includes the 0x prefix.

You cannot arbitrarily rearrange the flags. Fill only has meaning when followed by an alignment operator, the sign comes before # and 0, width comes before precision, and the type suffix comes last.

For normal work, start from the feature you need rather than assembling punctuation from memory. Use arguments and capture, width, alignment, and fill, precision, signs and zero padding, alternate formatting, or formatting traits for the individual pieces.

Use this page as the final lookup when those pieces are combined into one specification.