sprintf FORMAT, LIST

返回一个由 C 库函数 sprintf 的常用 printf 约定格式化的字符串。有关更多详细信息,请参见下文,并参见系统上的 sprintf(3)printf(3) 以了解一般原理。

例如

# Format number with up to 8 leading zeroes
my $result = sprintf("%08d", $number);

# Round number to 3 digits after decimal point
my $rounded = sprintf("%.3f", $number);

Perl 执行自己的 sprintf 格式化:它模拟 C 函数 sprintf(3),但除了浮点数以外不使用它,即使在使用时,也只允许标准修饰符。因此,您本地 sprintf(3) 中的非标准扩展在 Perl 中不可用。

printf 不同,当您将数组作为第一个参数传递给 sprintf 时,它不会执行您可能想要的操作。数组将被赋予标量上下文,并且 Perl 将使用数组中元素的计数作为格式,而不是使用数组的第 0 个元素作为格式,这几乎没有用处。

Perl 的 sprintf 允许以下普遍已知的转换

%%    a percent sign
%c    a character with the given number
%s    a string
%d    a signed integer, in decimal
%u    an unsigned integer, in decimal
%o    an unsigned integer, in octal
%x    an unsigned integer, in hexadecimal
%e    a floating-point number, in scientific notation
%f    a floating-point number, in fixed decimal notation
%g    a floating-point number, in %e or %f notation

此外,Perl 允许以下广泛支持的转换

%X    like %x, but using upper-case letters
%E    like %e, but using an upper-case "E"
%G    like %g, but with an upper-case "E" (if applicable)
%b    an unsigned integer, in binary
%B    like %b, but using an upper-case "B" with the # flag
%p    a pointer (outputs the Perl value's address in hexadecimal)
%n    special: *stores* the number of characters output so far
      into the next argument in the parameter list
%a    hexadecimal floating point
%A    like %a, but using upper-case letters

最后,为了向后(我们确实指的是“向后”)兼容性,Perl 允许这些不必要的但被广泛支持的转换

%i    a synonym for %d
%D    a synonym for %ld
%U    a synonym for %lu
%O    a synonym for %lo
%F    a synonym for %f

请注意,%e%E%g%G 生成的科学记数法中指数位数的数量,对于指数模数小于 100 的数字,是系统相关的:它可能是三个或更少(根据需要用零填充)。换句话说,1.23 乘以 10 的 99 次方可能是“1.23e99”或“1.23e099”。类似地,对于 %a%A:指数或十六进制数字可能会浮动:特别是“长双精度”Perl 配置选项可能会导致意外情况。

% 和格式字母之间,您可以指定几个额外的属性来控制格式的解释。按顺序,这些是

格式参数索引

一个显式的格式参数索引,例如 2$。默认情况下,sprintf 将格式化列表中下一个未使用的参数,但这允许您按顺序获取参数

printf '%2$d %1$d', 12, 34;      # prints "34 12"
printf '%3$d %d %1$d', 1, 2, 3;  # prints "3 1 1"
标志

一个或多个

space   prefix non-negative number with a space
+       prefix non-negative number with a plus sign
-       left-justify within the field
0       use zeros, not spaces, to right-justify
#       ensure the leading "0" for any octal,
        prefix non-zero hexadecimal with "0x" or "0X",
        prefix non-zero binary with "0b" or "0B"

例如

printf '<% d>',  12;   # prints "< 12>"
printf '<% d>',   0;   # prints "< 0>"
printf '<% d>', -12;   # prints "<-12>"
printf '<%+d>',  12;   # prints "<+12>"
printf '<%+d>',   0;   # prints "<+0>"
printf '<%+d>', -12;   # prints "<-12>"
printf '<%6s>',  12;   # prints "<    12>"
printf '<%-6s>', 12;   # prints "<12    >"
printf '<%06s>', 12;   # prints "<000012>"
printf '<%#o>',  12;   # prints "<014>"
printf '<%#x>',  12;   # prints "<0xc>"
printf '<%#X>',  12;   # prints "<0XC>"
printf '<%#b>',  12;   # prints "<0b1100>"
printf '<%#B>',  12;   # prints "<0B1100>"

当空格和加号作为标志同时给出时,空格将被忽略。

printf '<%+ d>', 12;   # prints "<+12>"
printf '<% +d>', 12;   # prints "<+12>"

当 # 标志和精度在 %o 转换中给出时,如果需要前导“0”,则精度将增加。

printf '<%#.5o>', 012;      # prints "<00012>"
printf '<%#.5o>', 012345;   # prints "<012345>"
printf '<%#.0o>', 0;        # prints "<0>"
向量标志

此标志告诉 Perl 将提供的字符串解释为整数向量,每个字符对应一个整数。Perl 依次将格式应用于每个整数,然后使用分隔符(默认情况下为点 .)连接生成的字符串。这对于显示任意字符串中字符的序数值很有用

printf "%vd", "AB\x{100}";           # prints "65.66.256"
printf "version is v%vd\n", $^V;     # Perl's version

v 之前放置一个星号 * 以覆盖用于分隔数字的字符串

printf "address is %*vX\n", ":", $addr;   # IPv6 address
printf "bits are %0*v8b\n", " ", $bits;   # random bitstring

您还可以使用类似 *2$v 的内容显式指定用于连接字符串的参数编号;例如

printf '%*4$vX %*4$vX %*4$vX',       # 3 IPv6 addresses
        @addr[1..3], ":";
(最小) 宽度

参数通常格式化为仅显示给定值所需的宽度。您可以通过在此处放置一个数字来覆盖宽度,或者从下一个参数(使用 *)或从指定参数(例如,使用 *2$)获取宽度

printf "<%s>", "a";       # prints "<a>"
printf "<%6s>", "a";      # prints "<     a>"
printf "<%*s>", 6, "a";   # prints "<     a>"
printf '<%*2$s>', "a", 6; # prints "<     a>"
printf "<%2s>", "long";   # prints "<long>" (does not truncate)

如果通过 * 获得的字段宽度为负数,则它与 - 标志具有相同的效果:左对齐。

精度,或最大宽度

您可以通过指定一个 . 后面跟着一个数字来指定精度(用于数字转换)或最大宽度(用于字符串转换)。对于除 gG 之外的浮点格式,这指定了小数点右侧显示多少位(默认值为 6)。例如

# these examples are subject to system-specific variation
printf '<%f>', 1;    # prints "<1.000000>"
printf '<%.1f>', 1;  # prints "<1.0>"
printf '<%.0f>', 1;  # prints "<1>"
printf '<%e>', 10;   # prints "<1.000000e+01>"
printf '<%.1e>', 10; # prints "<1.0e+01>"

对于 "g" 和 "G",这指定了要显示的最大有效数字位数;例如

# These examples are subject to system-specific variation.
printf '<%g>', 1;        # prints "<1>"
printf '<%.10g>', 1;     # prints "<1>"
printf '<%g>', 100;      # prints "<100>"
printf '<%.1g>', 100;    # prints "<1e+02>"
printf '<%.2g>', 100.01; # prints "<1e+02>"
printf '<%.5g>', 100.01; # prints "<100.01>"
printf '<%.4g>', 100.01; # prints "<100>"
printf '<%.1g>', 0.0111; # prints "<0.01>"
printf '<%.2g>', 0.0111; # prints "<0.011>"
printf '<%.3g>', 0.0111; # prints "<0.0111>"

对于整数转换,指定精度意味着数字本身的输出应使用此宽度进行零填充,其中 0 标志被忽略

printf '<%.6d>', 1;      # prints "<000001>"
printf '<%+.6d>', 1;     # prints "<+000001>"
printf '<%-10.6d>', 1;   # prints "<000001    >"
printf '<%10.6d>', 1;    # prints "<    000001>"
printf '<%010.6d>', 1;   # prints "<    000001>"
printf '<%+10.6d>', 1;   # prints "<   +000001>"

printf '<%.6x>', 1;      # prints "<000001>"
printf '<%#.6x>', 1;     # prints "<0x000001>"
printf '<%-10.6x>', 1;   # prints "<000001    >"
printf '<%10.6x>', 1;    # prints "<    000001>"
printf '<%010.6x>', 1;   # prints "<    000001>"
printf '<%#10.6x>', 1;   # prints "<  0x000001>"

对于字符串转换,指定精度会截断字符串以适合指定的宽度

printf '<%.5s>', "truncated";   # prints "<trunc>"
printf '<%10.5s>', "truncated"; # prints "<     trunc>"

您还可以使用 .* 从下一个参数获取精度,或从指定的参数获取精度(例如,使用 .*2$

printf '<%.6x>', 1;       # prints "<000001>"
printf '<%.*x>', 6, 1;    # prints "<000001>"

printf '<%.*2$x>', 1, 6;  # prints "<000001>"

printf '<%6.*2$x>', 1, 4; # prints "<  0001>"

如果通过 * 获得的精度为负数,则它被视为没有精度。

printf '<%.*s>',  7, "string";   # prints "<string>"
printf '<%.*s>',  3, "string";   # prints "<str>"
printf '<%.*s>',  0, "string";   # prints "<>"
printf '<%.*s>', -1, "string";   # prints "<string>"

printf '<%.*d>',  1, 0;   # prints "<0>"
printf '<%.*d>',  0, 0;   # prints "<>"
printf '<%.*d>', -1, 0;   # prints "<0>"
大小

对于数字转换,您可以使用 lhVqLll 指定解释数字的大小。对于整数转换(d u o x X b i D U O),数字通常被假定为平台上的默认整数大小(通常为 32 或 64 位),但您可以覆盖它以改为使用标准 C 类型之一,如用于构建 Perl 的编译器所支持的

hh          interpret integer as C type "char" or "unsigned
            char" on Perl 5.14 or later
h           interpret integer as C type "short" or
            "unsigned short"
j           interpret integer as C type "intmax_t" on Perl
            5.14 or later; and prior to Perl 5.30, only with
            a C99 compiler (unportable)
l           interpret integer as C type "long" or
            "unsigned long"
q, L, or ll interpret integer as C type "long long",
            "unsigned long long", or "quad" (typically
            64-bit integers)
t           interpret integer as C type "ptrdiff_t" on Perl
            5.14 or later
z           interpret integer as C types "size_t" or
            "ssize_t" on Perl 5.14 or later

请注意,通常情况下,在 Perl 代码中使用 l 修饰符(例如,在编写 "%ld""%lu" 而不是 "%d""%u" 时)是不必要的。此外,它可能是有害的,例如在 Windows 64 位系统上,long 是 32 位。

从 5.14 开始,如果它们在您的平台上不受支持,这些都不会引发异常。但是,如果启用了警告,则会发出 printf 警告类别的警告,以指示不支持的转换标志。如果您希望改为引发异常,请执行以下操作

use warnings FATAL => "printf";

如果您想在开始运行程序之前了解版本依赖关系,请在程序顶部添加类似以下内容

use v5.14;  # for hh/j/t/z/ printf modifiers

您可以通过 Config 了解您的 Perl 是否支持四元组

use Config;
if ($Config{use64bitint} eq "define"
    || $Config{longsize} >= 8) {
    print "Nice quads!\n";
}

对于浮点转换(e f g E F G),数字通常被假定为平台上的默认浮点大小(双精度或长双精度),但如果您平台支持,您可以使用 qLll 强制使用 "长双精度"。您可以通过 Config 了解您的 Perl 是否支持长双精度

use Config;
print "long doubles\n" if $Config{d_longdbl} eq "define";

您可以通过 Config 了解 Perl 是否将 "长双精度" 视为平台上要使用的默认浮点大小

use Config;
if ($Config{uselongdouble} eq "define") {
    print "long doubles by default\n";
}

长双精度和双精度也可能是一样的

use Config;
($Config{doublesize} == $Config{longdblsize}) &&
        print "doubles are long doubles\n";

大小说明符V对 Perl 代码没有影响,但为了与 XS 代码兼容而支持。它表示“使用 Perl 整数或浮点数的标准大小”,这是默认值。

参数顺序

通常,sprintf 将下一个未使用的参数作为每个格式说明的格式化值。如果格式说明使用*来要求额外的参数,这些参数将按照它们在格式说明中出现的顺序从参数列表中消耗,格式化值之前。当参数由显式索引指定时,这不会影响参数的正常顺序,即使显式指定的索引将是下一个参数。

所以

printf "<%*.*s>", $a, $b, $c;

使用$a作为宽度,$b作为精度,$c作为格式化值;而

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

将使用$a作为宽度和精度,$b作为格式化值。

以下是一些更多示例;请注意,在使用显式索引时,可能需要转义$

printf "%2\$d %d\n",      12, 34;     # will print "34 12\n"
printf "%2\$d %d %d\n",   12, 34;     # will print "34 12 34\n"
printf "%3\$d %d %d\n",   12, 34, 56; # will print "56 12 34\n"
printf "%2\$*3\$d %d\n",  12, 34,  3; # will print " 34 12\n"
printf "%*1\$.*f\n",       4,  5, 10; # will print "5.0000\n"

如果use locale(包括use locale ':not_characters')生效,并且POSIX::setlocale已被调用,则格式化浮点数中使用的十进制分隔符将受LC_NUMERIC区域设置的影响。参见perllocalePOSIX