Serenity Operating System
at master 140 lines 5.1 kB view raw view rendered
1# String Formatting 2 3Many places in Serenity allow you to format strings, similar to `printf()`, for example `DeprecatedString::formatted()` 4, `StringBuilder::appendff()`, or `dbgln()`. These are checked at compile time to ensure the format string matches the 5number of parameters. The syntax is largely based on 6the [C++ `std::formatter` syntax](https://en.cppreference.com/w/cpp/utility/format/formatter#Standard_format_specification) 7but there are some differences. 8 9For basic usage, any occurrences of `{}` in the format string are replaced with the other arguments, converted to string 10form, in order: 11 12```c++ 13DeprecatedString::formatted("Well, {} my {} friends!", "hello", 42) == "Well, hello my 42 friends!"; 14``` 15 16If you want to include a literal `{` in the output, use `{{`: 17 18```c++ 19DeprecatedString::formatted("{{ {}", "hello") == "{ hello"; 20``` 21 22You can refer to the arguments by index, if you want to repeat one or change the order: 23 24```c++ 25DeprecatedString::formatted("{2}{0}{1}", "a", "b", "c") == "cab"; 26``` 27 28To control how the arguments are formatted, add colon after the optional index, and then add format specifier 29characters: 30 31```c++ 32DeprecatedString::formatted("{:.4}", "cool dude") == "cool"; 33DeprecatedString::formatted("{0:.4}", "cool dude") == "cool"; 34``` 35 36## Format specifiers 37 38In order, the format can contain: 39 40- Fill character and alignment 41- Sign 42- `#` Hash 43- `0` Zero 44- Width 45- Precision 46- Type specifier 47 48Each of these is optional. You can include any combination of them, but they must be in this order. 49 50### Fill and alignment 51 52This is an optional fill character, followed by an alignment. The fill character can be anything apart from `{` or `}`, 53and is used to fill any space left when the input has fewer characters than the format requests. By default, it is a 54space. (` `) 55 56The alignment characters are: 57 58- `<`: Align left. 59- `>`: Align right. 60- `^`: Align centered. 61 62### Sign 63 64- `+`: Always display a sign before the number. 65- `-`: Display a sign for negative numbers only. 66- (space): Display a sign for negative numbers, and a leading space for other numbers. 67 68### Hash 69 70`#` causes an "alternate form" to be used. 71 72For integer types, this adds the number-base prefix after the sign: 73 74- `0b` for binary. 75- `0` for octal. 76- `0x` for hexadecimal. 77 78### Zero 79 80`0` pads the number with leading zeros. 81 82### Width and Precision 83 84The width defines the minimum number of characters in the output. The precision is a `.` followed by a precision number, 85which is used as the precision of floating-point numbers, or a maximum-width for string values. 86 87Both the width and precision can be provided as a replacement field (`{}`, optionally including an argument index) which 88allows you to use an integer argument instead of a hard-coded number. 89 90### Type specifiers 91 92| Type | Effect | Example output | 93|-----------|-----------------------|--------------------------| 94| *nothing* | default format | Anything! :^) | 95| b | binary | `110`, `0b000110` | 96| B | binary uppercase | `110`, `0B000110` | 97| d | decimal | `42`, `+0000042` | 98| o | octal | `043` | 99| x | hexadecimal | `ff0`, `0x00000ff0` | 100| X | hexadecimal uppercase | `FF0`, `0X00000FF0` | 101| c | character | `a` | 102| s | string | `well, hello friends!` | 103| p | pointer | `0xdeadc0de` | 104| f | float | `1.234`, `-inf` | 105| a | hex float | | 106| A | hex float uppercase | | 107| hex-dump | hexadecimal dump | `fdfdfdfd`, `3030 00` | 108 109Not all type specifiers are compatible with all input types, of course. 110 111## Formatting custom types 112 113You can provide a custom `AK::Formatter<Foo>` class to format `Foo` values. For the simplest case where you already have 114a function that produces a string from your type, that would look like this: 115 116```c++ 117template<> 118struct AK::Formatter<Web::CSS::Selector> : Formatter<StringView> { 119 ErrorOr<void> format(FormatBuilder& builder, Web::CSS::Selector const& selector) 120 { 121 return Formatter<StringView>::format(builder, selector.serialize()); 122 } 123}; 124``` 125 126More advanced formatters that make check for format-specifier flags can be written by referring to the fields 127in `StandardFormatter` (which most `Formatter` classes extend). 128 129## Detecting if a type can be formatted 130 131The `AK::HasFormatter<T>` template has a boolean value representing whether `T` can be formatted. 132 133The `FormatIfSupported<T>` makes use of this to return either the formatted value of `T`, or a series of `?`s if the 134type cannot be formatted. For example: 135 136```c++ 137// B has a Formatter defined, but A does not. 138DeprecatedString::formatted("{}", FormatIfSupported { A {} }) == "?"; 139DeprecatedString::formatted("{}", FormatIfSupported { B {} }) == "B"; 140```