-
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
V
andP
, 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