One specifier for four kinds
The specifier is parsed once, left to right, in a fixed order. Learning the order is learning the whole language; everything else is which type does what with the precision.
[[fill]align][sign][z][#][0][width][grouping][.precision][type]
| Part | Values | Meaning |
|---|---|---|
fill, align | *>, <, >, ^, = | padding character, and where the padding goes; = puts it after the sign |
sign | +, -, space | what to print before a non-negative number |
z | flag | a zero result is never negative |
# | flag | alternate form: prefixes for integers, kept zeros for floats |
0 | flag | zero padding, which participates in grouping |
width | digits | minimum columns |
grouping | ,, _ | thousands separators; _ groups binary, octal and hex by four |
.precision | digits | digits after the point for f, significant digits for g |
type | b c d e E f F g G n o x X % | presentation; none means "like a repr, with at least one decimal" |
Width, fill, alignment
@moonnum.format_int(1234567N, "15d")
@moonnum.format_int(1234567N, "<15d")
@moonnum.format_int(1234567N, "^15d")
@moonnum.format_int(1234567N, "*^15d")
@moonnum.format_int(1234567N, "0>15d")
| 1234567|
|1234567 |
| 1234567 |
|****1234567****|
|000000001234567|
Sign and zero padding
Zero padding goes inside the sign and, for other bases, inside the
prefix: -00001234567, 0x000_00ff. Padding outside
the sign is the classic bug that makes a column of numbers impossible to
align.
@moonnum.format_int(1234567N, "+15d")
@moonnum.format_int(-1234567N, "+15d")
@moonnum.format_int(1234567N, "015d")
@moonnum.format_int(-1234567N, "015d")
@moonnum.format_int(255N, "#010_x")
+1234567
-1234567
000000001234567
-00000001234567
0x000_00ff
Grouping that reaches into the zeros
With zero padding, the separators have to be inserted among the padding zeros too — otherwise the column stops lining up at exactly the values that need it most.
@moonnum.format_int(1234567N, ",d")
@moonnum.format_int(1234567N, "015,d")
@moonnum.format_int(255N, "_b")
@moonnum.format_float(1234.5678, ",.2f")
1,234,567
000,001,234,567
1111_1111
1,234.57
Precision means different things
f counts digits after the point, e counts digits
after the point and always writes an exponent, g counts
significant digits and drops trailing zeros. No type at all is
g with a guaranteed decimal: format(1.0, "") is
1.0, not 1.
@moonnum.format_float(1234.5678, "f")
@moonnum.format_float(1234.5678, ".2f")
@moonnum.format_float(1234.5678, ".3e")
@moonnum.format_float(1234.5678, ".3g")
@moonnum.format_float(1234.5678, "")
1234.567800
1234.57
1.235e+03
1.23e+03
1234.5678
Three flags that are easy to get wrong
# keeps the zeros g would drop;
z coerces a negative zero after rounding, before the sign is
chosen; % multiplies by a hundred, formats as f,
and appends a percent sign.
@moonnum.format_float(2.0, "g")
@moonnum.format_float(2.0, "#g")
@moonnum.format_float(-0.0, "")
@moonnum.format_float(-0.0, "z")
@moonnum.format_float(-0.0001, "z.2f")
@moonnum.format_float(0.25, ".2%")
2
2.00000
-0.0
0.0
0.00
25.00%
One entry point
format takes a Number and dispatches to the right
kind, so a table of mixed values can be printed with one specifier. A float
type on an integer converts it; a fraction formats exactly; a complex number
applies the specifier to both halves.
for text in ["42", "-0.5", "22/7", "3+4j"] {
println(@moonnum.format(@moonnum.parse(text), ".3f"))
}
42.000
-0.500
3.143
3.000+4.000j
Refusals
A specifier that cannot mean anything is refused rather than approximated:
precision on an integer, , on a hexadecimal number,
z on an integer, zero padding on a complex number, two grouping
characters at once. The offset is the position in the specifier that cannot
be read, which is where the caret should point.
@moonnum.format_int(255N, ".2d")
@moonnum.format_int(255N, ",x")
@moonnum.format_int(255N, "z")
@moonnum.format_float(1.5, "d")
precision is not allowed for integers at offset 2
cannot specify ',' with this presentation type at offset 1
negative-zero coercion is not allowed for integers at offset 0
unknown format code for a float at offset 0