The sprintf routine

Combined from primary sources listed below.

In Independent routines ( Type/independent-routines )§

See primary docmentation in context for routine sprintf.

routine sprintf§

multi sprintf(Cool:D $format, *@args)

Returns a string according to a format as described below. The format used is the invocant (if called in method form) or the first argument (if called as a routine).

sprintf"%s the %d%s", "þor", 1, "st").put# OUTPUT: «þor the 1st␤»
sprintf"%s is %s", "þor", "mighty").put;   # OUTPUT: «þor is mighty␤»
"%s's weight is %.2f %s".sprintf"Mjölnir", 3.3392, "kg").put;
# OUTPUT: «Mjölnir's weight is 3.34 kg␤»
# OUTPUT: «Mjölnir's weight is 3.34 kg␤»

This function is mostly identical to the C library's sprintf and printf functions. The only difference between the two functions is that sprintf returns a string while the printf function writes to a filehandle. sprintf returns a Str, not a literal.

The $format is scanned for % characters. Any % introduces a format token. Directives guide the use (if any) of the arguments. When a directive other than % is used, it indicates how the next argument passed is to be formatted into the string to be created. Parameter indexes may also be used in the format tokens. They take the form N$ and are explained in more detail below.

The $format may be defined enclosed in single or double quotes. The double-quoted $format string is interpolated before being scanned and any embedded string whose interpolated value contains a % character will cause an exception. For example:

my $prod = "Ab-%x-42";
my $cost = "30";
sprintf("Product $prod; cost: \$%d", $cost).put;
# OUTPUT: «Your printf-style directives specify 2 arguments, but 1 argument was supplied␤»
          «  in block <unitat <unknown fileline 1␤»

When handling unknown input you should avoid using such syntax by putting all variables in the *@args array and have one % for each in $format. If you need to include a $ symbol in the format string (even as a parameter index) either escape it or use the single-quoted form. For example, either of the following forms works without error:

sprintf("2 x \$20 = \$%d", 2*20).put# OUTPUT: «2 x $20 = $40␤»
sprintf('2 x $20 = $%d', 2*20).put;   # OUTPUT: «2 x $20 = $40␤»

In summary, unless you need something very special, you will have fewer unexpected problems by using the single-quoted format string and not using interpolated strings inside the format string.

[ 1 ]

Directives§

%a literal percent sign
ca character with the given codepoint
sa string
da signed integer, in decimal
uan unsigned integer, in decimal
oan unsigned integer, in octal
xan unsigned integer, in hexadecimal
ea floating-point number, in scientific notation
fa floating-point number, in fixed decimal notation
ga floating-point number, in %e or %f notation
Xlike x, but using uppercase letters
Elike e, but using an uppercase "E"
Glike g, but with an uppercase "E" (if applicable)
ban unsigned integer, in binary

Compatibility:

ia synonym for %d
Da synonym for %ld
Ua synonym for %lu
Oa synonym for %lo
Fa synonym for %f

Modifiers§

Modifiers change the meaning of format directives, but are largely no-ops (the semantics are still being determined).

hinterpret integer as native "short" (typically int16)
NYIlinterpret integer as native "long" (typically int32 or int64)
NYIllinterpret integer as native "long long" (typically int64)
NYILinterpret integer as native "long long" (typically uint64)
NYIqinterpret integer as native "quads" (typically int64 or larger)

Between the % and the format letter, you may specify several additional attributes controlling the interpretation of the format. In order, these are:

NYI Format parameter index using the '$' symbol§

An explicit format parameter index (ranging from 1 to N args) before the directive, such as %2$d. By default, sprintf will format the next unused argument in the list, but the parameter index allows you to take the arguments out of order (note single quotes are required unless you escape the $):

Without index:§

sprintf '%d %d', 12, 34;      # OUTPUT: «12 34␤»
sprintf '%d %d %d', 1, 2, 3;  # OUTPUT: «1 2 3␤»

NYI With index:§

The first example works as we expect it to when we index all directives.

sprintf '%2$d %1$d', 12, 34;      # OUTPUT: «34 12␤»

But notice the effect when mixing indexed and non-indexed directives in the second example (be careful what you ask for). The second, non-indexed directive gets the first argument, but it is also specifically requested in the last directive:

sprintf '%3$d %d %1$d', 1, 2, 3;  # OUTPUT: «3 1 1␤»

Flags§

One or more of:

spaceprefix non-negative number with a space
\+prefix non-negative number with a plus sign
-left-justify within the field
0use leading zeros, not spaces, for required padding
#ensure the leading "0" for any octal, prefix non-zero hexadecimal with "0x" or "0X", prefix non-zero binary with "0b" or "0B"
vNYI vector flag (used only with directive "d"), see description below

For example:

sprintf '<% d>',  12;   # OUTPUT: «< 12>␤»
sprintf '<% d>',   0;   # OUTPUT: «< 0>"»
sprintf '<% d>', -12;   # OUTPUT: «<-12>␤»
sprintf '<%+d>',  12;   # OUTPUT: «<+12>␤»
sprintf '<%+d>',   0;   # OUTPUT: «<+0>"»
sprintf '<%+d>', -12;   # OUTPUT: «<-12>␤»
sprintf '<%6s>',  12;   # OUTPUT: «< 12>␤»
sprintf '<%-6s>', 12;   # OUTPUT: «<12 >␤»
sprintf '<%06s>', 12;   # OUTPUT: «<000012>␤»
sprintf '<%#o>',  12;   # OUTPUT: «<014>␤»
sprintf '<%#x>',  12;   # OUTPUT: «<0xc>␤»
sprintf '<%#X>',  12;   # OUTPUT: «<0XC>␤»
sprintf '<%#b>',  12;   # OUTPUT: «<0b1100>␤»
sprintf '<%#B>',  12;   # OUTPUT: «<0B1100>␤»

When a space and a plus sign are given as the flags at once, the space is ignored:

sprintf '<%+ d>', 12;   # OUTPUT: «<+12>␤»
sprintf '<% +d>', 12;   # OUTPUT: «<+12>␤»

When the # flag and a precision are given in the %o conversion, the necessary number of 0s is added at the beginning. If the value of the number is 0 and the precision is 0, it will output nothing; precision 0 or smaller than the actual number of elements will return the number with 0 to the left:

say sprintf '<%#.5o>', 0o12;     # OUTPUT: «<00012>␤»
say sprintf '<%#.5o>', 0o12345;  # OUTPUT: «<012345>␤»
say sprintf '<%#.0o>', 0;        # OUTPUT: «<>␤» zero precision and value 0
                                 # results in no output!
say sprintf '<%#.0o>', 0o1       # OUTPUT: «<01>␤»

Vector flag 'v'§

This special flag (v, followed by directive d) tells Raku to interpret the supplied string as a vector of integers, one for each character in the string (the `ord` routine is used for the conversion to an integer). Raku applies the format to each integer in turn, then joins the resulting strings with a separator (a dot '.', by default). This can be useful for displaying ordinal values of characters in arbitrary strings:

NYI sprintf "%vd", "AB\x[100]";           # OUTPUT: «65.66.256␤»

You can also explicitly specify the argument number to use for the separator string by using an asterisk with a parameter index (e.g., *2$v); for example:

NYI sprintf '%*4$vX %*4$vX %*4$vX',       # 3 IPv6 addresses
        @addr[1..3], ":";

Width (minimum)§

Arguments are usually formatted by default to be only as wide as required to display the given value. You specify a minimum width that can override the default width by putting a number here, or get the desired width from the next argument (with * ) or from a specified argument (e.g., with *2$):

 sprintf "<%s>", "a";           # OUTPUT: «<a>␤»
 sprintf "<%6s>", "a";          # OUTPUT: «< a>␤»
 sprintf "<%*s>", 6, "a";       # OUTPUT: «< a>␤»
 NYI sprintf '<%*2$s>', "a", 6; # OUTPUT: «< a>␤»
 sprintf "<%2s>", "long";       # OUTPUT: «<long>␤» (does not truncate)

In all cases, the specified width will be increased as necessary to accommodate the given integral numerical value or string. If a field width obtained through * is negative, it has the same effect as the - flag: left-justification.

Precision, or maximum width§

You can specify a precision (for numeric conversions) or a maximum width (for string conversions) by specifying a . followed by a number. For floating-point formats, except g and G, this specifies how many places right of the decimal point to show (the default being 6). For example:

# These examples are subject to system-specific variation.
sprintf '<%f>', 1;    # OUTPUT: «"<1.000000>"␤»
sprintf '<%.1f>', 1;  # OUTPUT: «"<1.0>"␤»
sprintf '<%.0f>', 1;  # OUTPUT: «"<1>"␤»
sprintf '<%e>', 10;   # OUTPUT: «"<1.000000e+01>"␤»
sprintf '<%.1e>', 10; # OUTPUT: «"<1.0e+01>"␤»

For "g" and "G", this specifies the maximum number of digits to show, including those prior to the decimal point and those after it; for example:

# These examples are subject to system-specific variation.
sprintf '<%g>', 1;        # OUTPUT: «<1>␤»
sprintf '<%.10g>', 1;     # OUTPUT: «<1>␤»
sprintf '<%g>', 100;      # OUTPUT: «<100>␤»
sprintf '<%.1g>', 100;    # OUTPUT: «<1e+02>␤»
sprintf '<%.2g>', 100.01; # OUTPUT: «<1e+02>␤»
sprintf '<%.5g>', 100.01; # OUTPUT: «<100.01>␤»
sprintf '<%.4g>', 100.01; # OUTPUT: «<100>␤»

For integer conversions, specifying a precision implies the output of the number itself should be zero-padded to this width (where the 0 flag is ignored):

(Note that this feature currently works for unsigned integer conversions, but not for signed integer.)

sprintf '<%.6d>', 1;         # OUTPUT: «<000001>␤»
NYI sprintf '<%+.6d>', 1;    # OUTPUT: «<+000001>␤»
NYI sprintf '<%-10.6d>', 1;  # OUTPUT: «<000001 >␤»
sprintf '<%10.6d>', 1;       # OUTPUT: «< 000001>␤»
NYI sprintf '<%010.6d>', 1;  # OUTPUT: «< 000001>␤»
NYI sprintf '<%+10.6d>', 1;  # OUTPUT: «< +000001>␤»
sprintf '<%.6x>', 1;         # OUTPUT: «<000001>␤»
sprintf '<%#.6x>', 1;        # OUTPUT: «<0x000001>␤»
sprintf '<%-10.6x>', 1;      # OUTPUT: «<000001 >␤»
sprintf '<%10.6x>', 1;       # OUTPUT: «< 000001>␤»
sprintf '<%010.6x>', 1;      # OUTPUT: «< 000001>␤»
sprintf '<%#10.6x>', 1;      # OUTPUT: «< 0x000001>␤»

For string conversions, specifying a precision truncates the string to fit the specified width:

sprintf '<%.5s>', "truncated";   # OUTPUT: «<trunc>␤»
sprintf '<%10.5s>', "truncated"# OUTPUT: «< trunc>␤»

You can also get the precision from the next argument using .*, or from a specified argument (e.g., with .*2$):

sprintf '<%.6x>', 1;           # OUTPUT: «<000001>␤»
sprintf '<%.*x>', 6, 1;        # OUTPUT: «<000001>␤»
NYI sprintf '<%.*2$x>', 1, 6;  # OUTPUT: «<000001>␤»
NYI sprintf '<%6.*2$x>', 1, 4; # OUTPUT: «< 0001>␤»

If a precision obtained through * is negative, it counts as having no precision at all:

sprintf '<%.*s>',  7, "string";   # OUTPUT: «<string>␤»
sprintf '<%.*s>',  3, "string";   # OUTPUT: «<str>␤»
sprintf '<%.*s>',  0, "string";   # OUTPUT: «<>␤»
sprintf '<%.*s>', -1, "string";   # OUTPUT: «<string>␤»
sprintf '<%.*d>',  1, 0;          # OUTPUT: «<0>␤»
sprintf '<%.*d>',  0, 0;          # OUTPUT: «<>␤»
sprintf '<%.*d>', -1, 0;          # OUTPUT: «<0>␤»

Size§

For numeric conversions, you can specify the size to interpret the number as using l, h, V, q, L, or ll. For integer conversions (d u o x X b i D U O), numbers are usually assumed to be whatever the default integer size is on your platform (usually 32 or 64 bits), but you can override this to use instead one of the standard C types, as supported by the compiler used to build Raku:

(Note: None of the following have been implemented.)

hhinterpret integer as C type "char" or "unsigned char"
hinterpret integer as C type "short" or "unsigned short"
jinterpret integer as C type "intmax_t", only with a C99 compiler (unportable)
linterpret integer as C type "long" or "unsigned long"
q, L, or llinterpret integer as C type "long long", "unsigned long long", or "quad" (typically 64-bit integers)
tinterpret integer as C type "ptrdiff_t"
zinterpret integer as C type "size_t"

Order of arguments§

Normally, sprintf takes the next unused argument as the value to format for each format specification. If the format specification uses * to require additional arguments, these are consumed from the argument list in the order they appear in the format specification before the value to format. Where an argument is specified by an explicit index, this does not affect the normal order for the arguments, even when the explicitly specified index would have been the next argument.

So:

my $a = 5; my $b = 2; my $c = 'net';
sprintf "<%*.*s>", $a, $b, $c# OUTPUT: «< ne>␤»

uses $a for the width, $b for the precision, and $c as the value to format; while:

NYI sprintf '<%*1$.*s>', $a, $b;

would use $a for the width and precision and $b as the value to format.

Here are some more examples; be aware that when using an explicit index, the $ will need escaping if the format string is double-quoted:

sprintf "%2\$d %d\n",      12, 34;         # OUTPUT: «34 12␤␤»
sprintf "%2\$d %d %d\n",   12, 34;         # OUTPUT: «34 12 34␤␤»
sprintf "%3\$d %d %d\n",   12, 34, 56;     # OUTPUT: «56 12 34␤␤»
NYI sprintf "%2\$*3\$d %d\n",  12, 34,  3; # OUTPUT: « 34 12␤␤»
NYI sprintf "%*1\$.*f\n",       4,  5, 10; # OUTPUT: «5.0000␤␤»

Other examples:

NYI sprintf "%ld a big number", 4294967295;
NYI sprintf "%%lld a bigger number", 4294967296;
sprintf('%c', 97);                  # OUTPUT: «a␤»
sprintf("%.2f", 1.969);             # OUTPUT: «1.97␤»
sprintf("%+.3f", 3.141592);         # OUTPUT: «+3.142␤»
sprintf('%2$d %1$d', 12, 34);       # OUTPUT: «34 12␤»
sprintf("%x", 255);                 # OUTPUT: «ff␤»

Special case: sprintf("<b>%s</b>\n", "Raku") will not work, but one of the following will:

sprintf Q:b "<b>%s</b>\n",  "Raku"; # OUTPUT: «<b>Raku</b>␤␤»
sprintf "<b>
\%s</b>\n", "Raku"; # OUTPUT: «<b>Raku</b>␤␤»
sprintf "<b>%s
\</b>\n", "Raku"; # OUTPUT: «<b>Raku</b>␤␤»

In class Cool ( Type/Cool )§

See primary docmentation in context for method sprintf.

method sprintf§

method sprintf(*@args)

Returns a string according to a series of format directives that are common in many languages; the object will be the format string, while the supplied arguments will be what's going to be formatted according to it.

"% 6s".sprintf('Þor').say# OUTPUT: «   Þor␤»

Footnotes

1 |^| The information below is for a fully functioning sprintf implementation which hasn't been achieved yet. Formats or features not yet implemented are marked NYI.