-
Notifications
You must be signed in to change notification settings - Fork 19
String formatting
Dynamic strings offer enhanced formatting capabilities through functions such as str_format or str_val, modelled after format but with additional syntax and more specifiers and options.
str_format and similar expect a format string, formed from regular characters, copied directly to output, and placeholders, replaced by formatted arguments. str_val corresponds to a single format item without any additional syntax, where str_val(x, .format="f") is roughly equivalent to str_format("{0:f}", x) (except that the tag of x is known).
A new way of specifying format items is to use the { and } characters. The text between these braces specifies the string that shall replace the placeholder in the output. The initial { should be followed by an unsigned integer specifying the position of the argument (0-based). Next comes a colon (:), followed by the format string up to the first } character. The last character in the format string is a format selector which is used to select the proper type of the value and the allowed formatting options.
Braces that are not a part of a format item can be escaped with %{ and %}. Braces in a format item cannot be escaped in any way. An exception to this syntax is a valid color code (like {FF8000}), which is taken literally.
Braces can also wrap an expression. When encountered, this expression is parsed and executed, like with expr_parse. If the expression is valid, it may also be followed by :, in which case the result is formatted akin to the V selector.
Braces can also be used to specify the locale using a special syntax. All other occurrences of braces that don't match the rules specified above will raise an error.
Example:
str_format("{FFFFFF} %{{0:d}%} %{{1:f}%} %{{2:x}%}", 152, 8.63, 0xABCD); //{FFFFFF} {152} {8.63} {ABCD}To support backwards compatibility with most older format strings, the % character can be used as well to denote a format item, but with some syntax extensions. The % character shall be followed by any number of non-letter characters, and the first letter that follows is the format selector, ending the placeholder.
The initial % character may also be followed by a non-negative integer and a dollar sign ($) to indicate a positional argument, similarly to the brace syntax. A sequence of %% outside a format item denotes a literal % character.
All places where an integer is expected can also contain these special values:
| Pattern | Meaning | Example |
|---|---|---|
^ |
Incremented positional argument index. |
{^:d} {^:f} {^:s} is equivalent to %d %f %s. |
@index |
Positional argument at integer index. |
%0@1d formats a number with the number of leading zeroes in argument at index 1. |
-number |
The opposite value of number. |
A format selector is specified last in a format item, denoted by a letter and optionally preceded by options affecting the format.
| Letter | Format | Meaning | Example |
|---|---|---|---|
i |
[Cwidth][.precision] |
A signed integer in the decimal base, optionally with a specific width padded with C. If precision is given, the input is treated as fixed-width, with lower precision digits put after the decimal point and interpreted as if with f. |
8d pads the integer to the total width of 8 characters with spaces. .2d treats 1234 as 12.34. |
u |
[Cwidth][.precision] |
An unsigned integer in the decimal base, the rest is like for i. |
|
h or x
|
[Cwidth] |
An unsigned integer in the hexadecimal base, the rest is like for i. If forced to use on a float (such as with str_val or the V selector), formats it as a hex-float. |
|
o |
[Cwidth] |
An unsigned integer in the octal base, the rest is like for i. |
|
f |
[Cwidth][.precision] |
A floating point number, optionally with a fixed precision. If precision is negative, there are no padding decimal zeros. |
.3f turns 1.0 into 1.000. |
d |
[Cwidth][.precision] |
Behaves like i by default, but could also work like u or f if the tag is known. |
|
c |
[count] |
A single character, optionally repeated count times. |
3c produces AAA from 'A'. |
b |
[01[.width]] |
A bitset, using the specified 0 character for zeroes and the 1 character for ones. The total width is 32 or width, if specified. |
AB.8b produces AAAABBBB from 7. |
m |
[$][Cwidth][.precision] |
A monetary value, interpreted using the current locale, including the currency symbol. If $ is used, the currency symbol is local, otherwise an international abbreviation is used. Other values are interpreted like for i, with the difference that if precision is omitted, the smallest non-fractional unit for the currency is assumed. |
For en-US, the specifiers m, $m, $.0m, $.1m for the input 1234 result in USD12.34, $12.34, $1234.00, $123.40, respectively. |
t |
format[+hours[:minutes]] |
A Unix timestamp (returned by gettime) formatted as time in the current locale. Format must be valid according to std::put_time, and may optionally be followed by a UTC time zone offset (starting with + or -) in hours, and optionally also minutes. If the UTC offset is not specified, the time is interpreted in the local time zone. |
|
s |
[Cwidth][.size] |
An unpacked or packed string, optionally padded with C to a specified width, but not longer than size. |
.144s trims the input to the maximum chat line length. |
S |
[Cwidth][.size] |
A valid PawnPlus dynamic string; the options are the same as for s. |
|
q or e
|
[C[chars]] |
An escaped unpacked or packed string, with C as the escape character (\ is default), escaping all occurrences of characters in chars (\ and ' by default). |
%0$%%{}e escapes all occurrences of %, {, or }. |
Q or E
|
[C[chars]] |
An escaped PawnPlus dynamic string; the options are the same as for q or e. |
|
v |
A value with an unspecified type. | ||
V |
options |
A valid PawnPlus variant. If the variant denotes a value that can be represented by a format selector, the selector is used instead of V together with options. If options do not constitute valid options for the inner selector and they end on a letter that denotes a selector which would otherwise be valid in combination with the rest of the options, that combination is used instead. |
Both .3V and .3fV for var_new(1.00) act like .3f for 1.00. |
P |
options |
The result of pawn_arg_pack. Works like V. |
It is possible to set the current locale or encoding using the special syntax {$enc:identifier}, passing in a valid locale/encoding identifier. This sequence may be placed in any location in the format string outside a format item or another sequence in braces, even multiple times, to affect all selectors that follow. Use {$enc:} to reset the locale to its initial state (the global one).
The effects of setting a locale (whether through the special item or via pp_locale) are:
- For
i,f, and other numeric selectors (usinglocale_numeric), the number is formatted in a locale-specific format, such as by grouping decimal digits and including separators, or using a different decimal point character. - For
s,q,S,Q(usinglocale_ctype) the input string is converted from the default encoding to the set encoding, as if bystr_convert. - For
m(usinglocale_monetary), the number is formatted per the locale rules, and uses the currency used by the locale. - For
t(usinglocale_time), the result uses locale-specific number and time formatting and preferences. - For
VandP, the locale affects the formatting of the value stored inside as if used directly.
All selectors (with the exception of P) are associated with a specific tag and also serve to distinguish the form of the string within a particular tag (for example, S, Q and E are all associated with the String: tag). When the tag is retrieved, its format operation is used to obtain the string, or string if it fails.
Both parts of the process can be configured separately. For example, a selector may be registered for an already existing tag:
str_register_format('n', tag_uid_handle);
str_format("%n", handle_new(1)); //<1>Even though the Handle: tag is not aware of what the n selector does, it assumes the default format is desired if there are no parameters other than n. However, something like %03n would fail as the format is not understood by the tag.
This can be mitigated by creating a new tag and registering tag operations that handle the call:
forward String:PlayerNameFormat(playerid, type, String:format);
public String:PlayerNameFormat(playerid, type, String:format)
{
if(!IsPlayerConnected(playerid)) return STRING_NULL;
new name[MAX_PLAYER_NAME+1];
GetPlayerName(playerid, name, sizeof name);
return str_new(name);
}
new tag_uid:uid = tag_new("PlayerName");
tag_set_op(uid, tag_op_format, "PlayerNameFormat");
tag_lock(uid);
if(!str_register_format('p', uid))
{
printf("Could not register the format operation to tag %d.", uid);
}
str_format("%p", 0); //name of the player