Perl的print系列函数使用参考
2017-10-07 22:23:31 阿炯

Perl中的向终端或文件句柄中输出的基本函数,本文涵盖如下三个函数:print、printf、sprintf。

详细用法可以查看perl用户手册:perldoc -f print printf sprintf

print系列函数其各自支持的命令格式,都有三四种,但是常用的也就一两种。

perl print函数 - 打印表达式中列表​值到当前默认的输出文件句柄。

语法
print FILEHANDLE LIST
print LIST
print

定义和用法
打印表达式中列表值到当前默认的输出文件句柄,或到一个指定的文件句柄。
如果设置,则将$\变量添加到列表 LIST 的末尾。
如果列表 LIST 是空的,$_的值将被打印代替。
打印接受列表的值,列表中的每一个元素将被解释为一个表达式。

返回值:
0 - 失败
1 - 成功

示例:
$string = "That is test";
@list = (1,2,3,4,5,6,);
$index = index ($string, 'is');

print "Position of is in the string $index\n";
print "Print list @list\n";

这将输出以下结果:
Position of is in the string 5
Print list 1 2 3 4 5 6

-----------------------------
printf 函数
将列表LIST的值通过指定的格式打印到当前输出文件句柄,或一个指定的文件句柄。

语法
printf FILEHANDLE FORMAT,LIST
printf FORMAT,LIST

定义和用法
打印解释,通过指定的格式格式到当前输出文件句柄值的列表LIST,或一个指定的文件句柄。

实际上相当于打印FILEHANDLE的sprintf(FORMAT,LIST)

可以使用printf打印的情况:如果并不需要一个特定的输出格式。printf函数先格式化字符串再输出到指定文件或当前缺省文件中,如:
printf OUTFILE (“You owe me %8.2f",$owing);

此语句取出变量$owing的值并替换掉串中的%8.2f,%8.2f是域格式的例子,把$owing的值看作浮点数。

以下是公认的格式转换。
Format     Result
%%     A percent sign
%c     A character with the given ASCII code
%s     A string
%d     A signed integer (decimal)
%u     An unsigned integer (decimal)
%o     An unsigned integer (octal)
%x     An unsigned integer (hexadecimal)
%X     An unsigned integer (hexadecimal using uppercase characters)
%e     A floating point number (scientific notation)
%E     A floating point number, uses E instead of e
%f     A floating point number (fixed decimal notation)
%g     A floating point number (%e or %f notation according to value size)
%G     A floating point number (as %g, but using .E. in place of .e. when appropriate)
%p     A pointer (prints the memory address of the value in hexadecimal)
%n     Stores the number of characters output so far into the next variable in the parameter list

Perl也支持,有选择地调整输出格式的标志,这些被指定%和转换字母。它们显示在下面的表中:
Flag     Result
space     Prefix positive number with a space
+     Prefix positive number with a plus sign
-     Left-justify within field
0     Use zeros, not spaces, to right-justify
#     Prefix non-zero octal with .0. and hexadecimal with .0x.
number     Minimum field width
.number     Specify precision (number of digits after decimal point) for floating point numbers
l     Interpret integer as C-type .long. or .unsigned long.
h     Interpret integer as C-type .short. or .unsigned short.
V     Interpret integer as Perl.s standard integer type
v     Interpret the string as a series of integers and output as numbers separated by periods or by an arbitrary string extracted from the argument when the flag is preceded by *.

printf函数有一个模板,叫格式字符串,它可以规定输出的格式,每个格式符有百分号开头,由字母结束。格式化字符串中有3个格式符,则对应3个元素。
%g 输出数字,它将根据需要自动选用浮点数,整数或者指数
%d 十进制整数,%x 十六进制,%o八进制,根据需要截尾;无条件截断(非四舍五入)
%f or %s 限制宽度 其中正数是右对齐,负数是左对齐
%s 是针对字符串的,如%10s, %-15s
%f 针对数字的,如%12.3f (表示输出共12个字符,包括小数点,并且小数点后面只有3位数)
%% 输出百分号,不会使用后面列表中的元素

printf的显示位宽度也可以作为参数来另外指定:先在格式字符串中用'*'占位,接下来第一个参数是宽度,第二个是字符串内容:
printf "%*s",9,'FreeOA';    #前置空格

也可以用两个'*'表示浮点数的总宽度和小数部分的宽度:
use constant PI => 4 * atan2(1, 1);
printf "%*.*f",7,2,PI;

返回值:同print。

示例
打印数组的第1,2字段值:
printf "%-50s%-20s\n",$arr[0],$arr[1];

my @a=qw(FreeOA good-bye);
printf"".("%20s\n" x @a) ,@a;
(printf"%20s\n,%20s\n",@a;)  #:printf输出格式只是针对一个元素,所以想输出所有元素的格式,就要输出所有的形式,或者用“x”这个来完成。

-----------------------------
sprintf 函数
在LIST的值的基础上返回一个格式化字符串。

语法
sprintf FORMAT,LIST

定义和用法
返回一个格式化字符串在LIST的值的基础上。本质上等同于printf,但格式的字符串返回,而不是被直接打印。

返回值
SCALAR,一个格式化的文本字符串。

$text = sprintf("%0d\n", 9);
print "Formated string is $text\n";

结果:
Formated string is 9

$result = sprintf('The %s is %d', 'answer', 42);

my @items = qw(wilma dino freeoa pebbles);
my $format = "The items are:\n" . ("%10s\n" x @items);
# print "the format is <<$format>>\n";for debugging
printf $format, @items;

三者的区别
指令  描述
print  打印信息,可以输出到文件里。
printf  可以整理信息的格式,可以输出到文件里。与sprintf类似,区别是可以直接打印。
sprintf  可以整理信息的格式。与printf类似,区别是仅仅用于字符串的格式化,没有任何print效果。

-----------------------------
对say的解析

print、printf和say都可以输出信息。print和say类似,print不自带换行符,say自带换行符,但要使用say,Perl版本必须在5.10之上:'use 5.010;',printf像C语言的printf一样,可以定制输出格式。它们有返回值:如果输出成功,就返回1。另外注意perl中有上下文的概念,这几个输出操作也同样有上下文环境:列表上下文。
@arr=qw(hello world);
print "hello world","\n";
print "hello world\n";  
print @arr;    # 输出helloworld(没空格)
print "@arr";    # 输出hello world(有空格)

print/say可以以函数格式(print(args)/say(args))进行输出,这时候有个陷阱需要注意;示例如下:
print(3+4)*4;

这个返回7,而不是28。这是如何计算的?

Perl中很多时候是可以省略括号的,这往往让人忘记括号的归属。而Perl中又有上下文的概念,在不同上下文执行同一个操作的结果是不一样的。在这里:
1.print不加括号的时候,它需求的参数是一个列表上下文,它后面的所有内容都会被print输出;
2.print加括号的时候,它只会输出括号中的内容。

所以上面的语句等价于:(print(3+4))*4

它先执行print(7),然后拿到print的返回值1,将其乘以4,由于没有赋值给其它变量,所以这个乘法的结果被丢弃。如果将上面赋值给一个变量:
$num = print(3+4)*4;
则$num的值将为4。

如果想要输出(3+4)*4=28的结果,可以将它们放在一个括号里,或者在(3+4)的括号前加一个+号,它表示让它后面的表达式作为函数的参数,相当于加个括号。所以下面两个是等价的语句:
print ((3+4)*4);
print +(3+4)*4;

另外由于print/say不使用括号的时候,它们会输出其后面的列表。所以有以下技巧:
1.像cat命令一样,直接输出文件内容:print <>;
2.像sort命令一样,排序文件内容:print sort <>;

---------------------------
print 的进一步理解

没有括号的时候,print是列表操作符,会把其后列表里所有东西都数出来。但是假如print后面紧跟着左括号,它就是一个函数调用,只会将括号内的东西输出来。“假如它看起来像函数调用,它就是一个函数调用";如果print(或其他函数)后面接着一个左括号,请务必确定在函数的所有参数也有相应的右括号。

print(2+3)*4; # 输出5,print 后边有括号当成函数调用,打印输出5之后返回1乘以4,之后将结果抛弃。

printf 格式化最常用用法
printf 操作符的参数包括“格式字符串”及“要输出的数据列表”。
格式字符串好像用来填空的模版,代表你想要的输出格式:
printf "Hello,%s;your password expires in %d days!\n",$user,$day_to_die;

每种转换都会以百分比符号(%)开头,然后以某个字母结尾。而后面的列表里元素的个数应该和转换的数目一样多,如果数目不对,就无法正确运行。
%d 格式则代表十进制整数,它会舍去小数点后的额数字(请注意,它会无条件截断,而非四舍五入)
%g 自动选择浮点数,整数甚至是指数形式
%s 代表字符串格式,功能其实就是字符内插,只是还能设定字符宽度
%f 浮点数格式转换,会按照四舍五入,可以指定小数点后的输出位置
   %12f
   %12.3f
   %12.0f
%x 代表十六进制,%o代表八进制

如果要输出真正的百分号,请使用%%。

%10s 输出字符串右对齐,空格补位
%6d  输出结果会左端有空格 右对齐
如果宽度为负数,则会向左对齐
 
数组和printf

需要些技巧来解决这个问题。

my @items = qw(david xinxin huahua);
my $format = "The item are:\n" . ("%-10s\n" x @items);
print "The format is >>$format<<\n";
printf $format,@items;


旗标(flags)
-    让输出内容左对齐指定字段
+    在正数前添加一个加号(+),在负数前添加一个减号(-)
空格    在一个并非用'+'标记打印的正数前加一个空格
零(0)    用前置的'0'来填充字段
#    与八进制转换定义符(o)一起使用时,为输出加上前缀0;与十六进制转换定义符(x或X)一起使用时为输出加上前缀0x或0X,二进制则为0b或0B。
    在用e、E、f、g或G输出不带小数部分的浮点数中,强制加上小数点(通常只有在小数点后有1个数位时,小数点才会输出);对
    于g和G定义符来说,追尾的0(零)不能删除的。

在格式化控制字串中使用旗标,应将其放在百分号的正右边。几个旗标可以在一个转换说明中结合使用。

-----------------------------
官方sprintf函数手册(基于v5.38+)

perl printf函数 - 打印解释,通过指定的格式格式到当前输出文件句柄值的列表LIST,或一个指定的文件句柄。

语法
printf FILEHANDLE FORMAT, LIST

printf FORMAT, LIST

定义和用法
打印解释,通过指定的格式格式到当前输出文件句柄值的列表LIST,或一个指定的文件句柄。

实际上相当于打印FILEHANDLE的sprintf(FORMAT,LIST)

按照 C library 函数 sprintf 的通常 printf 约定格式化的字符串。并参阅系统上的 sprintf(3) 或 printf(3) 以了解一般性原则的解释。

# 格式化数字,最多包含 8 个前导零
my $result = sprintf("%08d", $number);

# 将数字四舍五入到小数点后 3 位
my $rounded = sprintf("%.3f", $number);

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

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

Perl 的 sprintf 允许以下众所周知的转换;可以使用printf打印的情况:如果并不需要一个特定的输出格式。

以下是公认的格式转换。
Format     Result
%%     A percent sign
%c     A character with the given ASCII code
%s     A string
%d     A signed integer (decimal)
%u     An unsigned integer (decimal)
%o     An unsigned integer (octal)
%x     An unsigned integer (hexadecimal)
%f     A floating point number (fixed decimal notation)
%g     A floating point number (%e or %f notation according to value size)
%e     A floating point number (scientific notation)

%X     An unsigned integer, like %x (hexadecimal using uppercase characters)
%E     A floating point number, uses E instead of e
%G     A floating point number (as %g, but using .E. in place of .e. when appropriate)
%p     A pointer (prints the memory address of the value in hexadecimal)
%n     Stores the number of characters output so far into the next variable in the parameter list
%a   Hexadecimal floating point
%A   Like %a, but using upper-case letters
%b   An unsigned integer, in binary
%B   Like %b, but using an upper-case "B" with the # flag

最后,为了向后("backward" )兼容, 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

注意,对于指数模数小于 100 的数字,%e、%E、%g 和 %G 生成的科学计数法中的指数位数取决于系统:可能是 3 个或更少(必要时用零填充)。换句话说,1.23 乘以 10 的 99 次方可能是 "1.23e99" 或 "1.23e099"。对于 %a 和 %A 也类似:指数或十六进制数字可能会浮动:尤其是 "long doubles",Perl 配置选项可能会带来意外结果。

在 % 和格式字母之间可以指定几个控制格式解释的附加属性。按顺序,这些属性是:

格式参数索引

显式格式参数索引,例如 2$ 。默认情况下,sprintf 将格式化列表中的下一个未使用的参数,但这允许您无序地获取参数:
printf '%2$d %1$d', 12, 34;    # 打印  "34 12"
printf '%3$d %d %1$d', 1, 2, 3;    # 打印  "3 1 1"

Flags

Perl支持有选择地调整输出格式的标志。这些被指定%和转换字母。它们显示在下面的表中:
Flag     Result
space     Prefix positive number with a space
+     Prefix positive number with a plus sign
-     Left-justify within field
0     Use zeros, not spaces, to right-justify
#     Prefix non-zero octal with .0. and hexadecimal with .0x, binary with .0b.
number     Minimum field width
.number     Specify precision (number of digits after decimal point) for floating point numbers(为浮点数指定精度(小数点后的位数))

l     Interpret integer as C-type .long. or .unsigned long.
h     Interpret integer as C-type .short. or .unsigned short.
V     Interpret integer as Perl.s standard integer type
v     Interpret the string as a series of integers and output as numbers separated by periods or by an arbitrary string extracted from the argument when the flag is preceded by *.

示例
printf "%d\n", 3.1415126;
printf "The cost is \$%6.2f\n",499;
printf "Perl's version is v%vd\n",%^V;

这将产生以下结果:
3
The cost is $499.00
Perl's version is v5.32.1


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;    # 打印  "<+12>"

当在 %o 转换中给出 # 标志和精度时,如果前导 "0" 需要,则精度会增加。
printf '<%#.5o>', 012;    # 打印  "<00012>"
printf '<%#.5o>', 012345;    # 打印  "<012345>"
printf '<%#.0o>', 0;    # prints "<0>"

vector flag

此标志告诉 Perl 将提供的字符串解释为整数向量,字符串中的每个字符对应一个整数向量。Perl 依次将格式应用于每个整数,然后用分隔符(默认情况下为点 . )连接生成的字符串。这对于显示任意字符串中字符的序数值很有用:
printf "%vd", "AB\x{100}";    # 打印  "65.66.256"
printf "version is v%vd\n", $^V;    # Perl 的版本

在 v 之前放置一个星号 * 来覆盖用于分隔数字的字符串:
printf "address is %*vX\n", ":", $addr;   # IPv6 地址
printf "bits are %0*v8b\n", " ", $bits;   # 随机位串

还可以使用类似 *2$v 之类的东西明确指定用于连接字符串的参数编号;例如:
printf '%*4$vX %*4$vX %*4$vX', @addr[1..3], ":";        # 3 IPv6 地址

(minimum) width

该参数通常被格式化为仅显示给定值所需的宽度。可以通过在此处输入数字来覆盖宽度,或者从下一个参数(使用 * )或从指定参数(例如使用 *2$ )获取宽度:
printf "<%s>", "a";        #  "<a>"
printf "<%6s>", "a";    # "<     a>"
printf "<%*s>", 6, "a";    # "<     a>"
printf '<%*2$s>', "a", 6;    #  "<     a>"
printf "<%2s>", "long";    #  "<long>" (不截断)

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

C语言的库函数手册中在"Format of the format string"章节有对'*'与'N$'的说明:
The arguments must correspond properly (after type promotion) with the conversion specifier. By default, the arguments are used in the order given, where each '*' (see Field width and Precision below) and each conversion specifier asks for the next argument (and it is an error if insufficiently many arguments are given). One can also specify explicitly which argument is taken, at each place where an argument is required, by writing "%m$" instead of '%' and "*m$" instead of '*', where the decimal integer m denotes the position in the argument list of the desired argument, indexed starting from 1. Thus,
实参必须(在类型提升之后)与转换说明符适当对应。默认情况下,参数按照给定的顺序使用,其中每个'*'(请参阅下面的字段宽度和精度)和每个转换说明符都会请求下一个参数(如果给出的参数不够多,则会产生错误)。还可以显式指定在需要参数的每个位置使用哪个参数,方法是用"%m$"代替"%",用"*m$"代替"*",其中十进制整数m表示所需参数在参数列表中的位置,从1开始索引。因此,

printf("%*d", width, num);
and
printf("%2$*1$d", width, num);

are equivalent. The second style allows repeated references to the same argument. The C99 standard does not include the style using '$', which comes from the Single UNIX Specification. If the style using '$' is used, it must be used throughout for all conversions taking an argument and all width and precision arguments, but it may be mixed with "%%" formats, which do not consume an argument. There may be no gaps in the numbers of arguments specified using '$'; for example, if arguments 1 and 3 are specified, argument 2 must also be specified somewhere in the format string.
是等价的。第二种风格允许重复引用相同的参数。C99标准不包括使用'$'的样式,它来自单一UNIX规范。如果使用使用'$'的样式,则必须在所有接受参数以及所有宽度和精度参数的转换中使用它,但它可以与不使用参数的"%%"格式混合使用。使用'$'指定的参数数量可能没有空白;例如,如果指定了参数1和3,则必须在格式字符串的某个位置指定参数2。


精度,或最大宽度

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

# 这些示例可能会因系统特定而发生变化
printf '<%f>', 1;    # 打印  "<1.000000>"
printf '<%.1f>', 1;  # 打印  "<1.0>"
printf '<%.0f>', 1;  # 打印  "<1>"
printf '<%e>', 10;   # 打印  "<1.000000e+01>"
printf '<%.1e>', 10; # 打印  "<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";   # 打印  "<trunc>"
printf '<%10.5s>', "truncated"; # 打印  "<     trunc>"

还可以使用 '.*' 从下一个参数获取精度,或者从指定参数(如上所使用 .*2$ )获取精度:
printf '<%.6x>', 1;       # prints "<000001>"
printf '<%.*x>', 6, 1;    # prints "<000001>"
printf '<%.*2$x>', 1, 6;  # 打印  "<000001>"
printf '<%6.*2$x>', 1, 4; # 打印  "<  0001>"

如果通过 * 获得的精度为负数,则算作根本没有精度。
printf '<%.*s>',  7, "string";   # prints "<string>"
printf '<%.*s>',  3, "string";   # 打印  "<str>"
printf '<%.*s>',  0, "string";   # prints "<>"
printf '<%.*s>', -1, "string";   # 打印  "<string>"

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

size

对于数字转换,可以指定大小来解释数字,使用 l 、 h 、 V 、 q 、 L 或 ll 。对于整数转换( 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 位。

从 v5.14 开始,如果所用的平台不支持这些,则 none 会引发异常。但如果启用了警告,则在不支持的转换标志上会发出 printf 警告类的警告。如果更喜欢异常,请执行以下操作:
use warnings FATAL => "printf";

如果想在开始运行程序之前了解版本依赖关系,请在其顶部放置如下内容:
use v5.14;  # 用于 hh/j/t/z/ printf 修饰符

可以通过 Config 检查您的 Perl 是否支持quads:
use Config;
if ($Config{use64bitint} eq "define" || $Config{longsize} >= 8) {
    print "Nice quads!\n";
}

对于浮点转换( e f g E F G ),数字通常被假定为平台上的默认浮点大小(双精度或长双精度),但如果平台支持,可以使用 q 、 L 或 ll 强制使用 "long double" 。可以通过 Config 了解所使用的 Perl 是否支持长双精度:
use Config;
print "long doubles\n" if $Config{d_longdbl} eq "define";

可以通过 Config 了解 Perl 是否将 "long double" 视为所用的平台上使用的默认浮点大小:
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 代码兼容。它表示 "use the standard size for a Perl integer or floating-point number" ,这是默认值。

参数顺序

通常情况下, sprintf 将下一个未使用的参数作为每个格式规范的格式值。如果格式规范使用 * 来要求附加参数,则这些参数将按照它们在格式规范中出现的顺序从参数列表中使用before要格式化的值。如果参数由显式索引指定,则这不会影响参数的正常顺序,即使显式指定的索引是下一个参数。

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

使用 $a 作为宽度、使用 $b 作为精度、使用 $c 作为要格式化的值;而:
printf '<%*1$.*s>', $a, $b;
将使用 $a 作为宽度和精度,并使用 $b 作为格式化的值。

这里还有更多示例;请注意,当使用显式索引时,$ 可能需要转义:
printf "%2\$d %d\n", 12, 34;     # 将打印  "34 12\n"
printf "%2\$d %d %d\n", 12, 34;     # 将打印  "34 12 34\n"
printf "%3\$d %d %d\n", 12, 34, 56; # 将打印  "56 12 34\n"
printf "%2\$*3\$d %d\n", 12, 34,  3; # 将打印  " 34 12\n"
printf "%*1\$.*f\n", 4,  5, 10; # 将打印  "5.0000\n"

如果 use locale(包括 use locale ':not_characters' )生效并且已调用 POSIX::setlocale,则格式化浮点数中用于小数分隔符的字符将受到 LC_NUMERIC 区域设置的影响。请参阅 perllocale 和 POSIX。

---------------------------
Using (s)printf()

本文在些引用该文章并进行部分的翻译,其文发表于2000年,距今已经过去25载,但仍值得一看。

printf 和 sprintf 函数的工作方式与C库函数中的一样,只是有一些细微的区别。printf提供了对值格式的大量控制,这正是它的目的所在。如果曾经想要制作一个表现良好的、与字段对齐的报告,四舍五入到整数或特定的小数点,获得值的八进制或十六进制表示,或者只是以任何其他可以想象的形式显示您的值,它俩将提供这样做的实用程序,甚至更多。

printf() versus sprintf()
printf()和sprintf()看起来是一样的。也就是说,无论传递给其中一个的参数是什么,都可以不加更改地传递给另一个。不同之处在于printf打印到一个文件句柄,而sprintf返回printf应该输出的字符串。

要在STDOUT以外的文件句柄上使用printf(),请指定要使用的文件句柄,就像使用print一样,如下所示:
printf(HANDLE $format, @values);

结果将被print到HANDLE上。sprintf不接受文件句柄,而是将输出返回为字符串。
my $string = sprintf($format, @values);

格式字符串

printf()中的格式字符串是一些标记,它们描述如何打印所提供的变量,以及想要的任何其他内容。每个变量格式说明符以%开头,后跟零个或多个可选修饰符,并以转换说明符结束。

一个典型的格式字符串看起来像这样:
"foo is %d"

打印出来,它可能看起来像:'foo is 12'。%d被在格式字符串参数后指定的变量替换。在这种情况下可以按如下操作:
printf("foo is %d", $decimal);

因此,%d被替换为$decimal的值。可以在格式字符串中放入任意数量的说明符,并使用与说明符相同数量的后续参数。一个示例如下:
printf("%d %s %f", $decimal, $string, $float);

转换说明符

把这些放到你的格式字符串中。除%%外,每个参数都被printf参数列表中的相应值所替换。

%% prints a single % (percent sign:百分号).
%c prints a single character with the given ASCII number (66 is printed as B, for example).将数字转化为字符
%s prints a given string.字符串
%d a signed integer in decimal.带符号的十进制
%u an unsigned (can't be negative) 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 same as %e or %f, whichever printf thinks is best.浮点数,包括%e和%f

作为常用格式的补充,Perl还运行几种不在标准printf()格式:
%X is the same as %x, except it uses upper-case letters.类似于%x,但使用大写字母
%E like %e, but with an upper-case 'E'.类似于%e,但使用大写字母
%G same as %E when scientific notation is used for the value.类似于%g,但使用大写字母
%p a pointer; it outputs Perl's value address in hexadecimal.指针(以十六进制输出Perl地址)
%n an odd little bugger that *stores* (in the variable given for the position) the number of characters output so far.特称:将目前为止输出的字符个数“存储”在参数列表中的下一个变量中

其他仅仅是为了向后兼容而存在的:
%i synonym for %d
%D same as %ld (long decimal)
%U same as %lu (long unsigned decimal)
%O same as %lo (long octal)
%F same as %f

在必须的百分号及一个代表格式的字母方式外,也可以通过在其之间插入一些其它属性来控制所要输出的结果:
sprintf "%9s", 'FreeOA';    #强制输出结果右对齐且长度为9个字符,如果要左对齐则在紧跟%符号后插入一个'-'

想强制控制输出字符的最大长度,在'.'之后加一个数字:printf "%.7s",$str;
组合使用可控制最大与最小长度:printf "%min.max",$str;    #最短长度为min,最长为max
为了保证输出的每个字串的长度一致,可将其最长与最短长度设置相等值。更多用法可参数下面的旗标节。

格式说明符

以下每个项目都是可选的(除非另有说明),并应按照它们在这里出现的顺序使用。如果这让人感到困惑,请跳到下一节。其目的是作为一个参考,并复制了一些额外的解释和例子。

% - a percent sign. This is required, of course.

下列零项或多项:
'#'(井号):指定该值应转换为'替代形式'。这对“c”、“d”、“i”、“n”、“p”、“s”和“u”转换没有影响。对于'o'(八进制)转换,在开头加上一个'0'。对于'x'和'X'(十六进制),在值前加上0x或0X。对于‘e’,‘E’,‘f’,‘g’和‘G’,即使后面没有数字,也总是以小数点(.)结尾打印值。对于‘g’和‘g’,不会从结果中删除末尾的零。

printf("%x", 10);    # prints just 'a', versus:
printf("%#x", 10);    # prints '0xa'

'0'(零):指定数字的零填充。转换后的值在左侧用指定的零数减去要打印的位数填充。下面将对此进行更详细的描述。
printf("%03d", 7);    # prints '007'
printf("%03d", 153);    # prints '153'

'-'(减号):指定负字段宽度。这表明该值应该在边界上向左调整,而不是默认的向右调整。有关如何指定字段宽度的更多信息,请参见下文。
printf("%5s", 'foo');    # prints '  foo'
printf("%-5s", 'foo');    # prints 'foo  '

' '(空格):指定在正数前留下空白
printf("% d", 7);    # prints ' 7'
printf("% d", -7);    # prints '-7'

'+'(加号):指定在值之前总是放置一个符号。如果同时使用'+'将覆盖' '(空格)。
printf("%+d", 7);    # prints '+7'

指定最小字段宽度的十进制数字。使用'-'修饰符(见上文)将值左对齐,否则将值右对齐。使用用于数字转换的'0'修饰符,将值右填充零以填充字段宽度。
printf("%5s", 'foo');    # prints '  foo'
printf("%-5s", 'foo');    # prints 'foo  '

句点('.')形式的精度值,后跟一个可选的数字字符串。如果省略数字字符串,则使用零精度。这指定了‘d’,‘i’,‘o’,‘u’,‘x’和‘X’转换要打印的最小位数。对于‘e’、‘E’和‘F’转换,它是小数点后出现的位数。对于‘g’和‘G’转换,它指定有效位数的最大数目。对于‘s’(字符串)转换,它是要打印的字符串的最大字符数。使用后者来确保长字符串不会超过其字段宽度。
printf("%.3d", 7);    # prints '007'
printf("%.2f", 3.66666);    # prints '3.66'
printf("%.3s", 'foobar');    # prints 'foo'

这里的字符'h'将指定将十进制值视为C类型'short'或'unsigned short'。
printf("%hd\n", 400000);    # prints '6784'

字符'l'(ell)可用于将值视为C的'long'类型。

字符'V'将把一个整数解释为Perl的标准整数类型。
printf("%Vd", 7);    # prints '7'

最后是所需的转换说明符,前一节列出了有效的转换。

前导零

假设你有一个数字,比如642,想把它输出为00642。%0nC说明符语法允许您这样做,其中'n'是字段宽度,而C是您想使用的转换说明符。字段宽度是值应该填充的最小字符数(在本例中)。任何小于该值的值都将通过在值前加上零来填充余数,直到完全匹配为止。
printf("%05d", 642);    # outputs '00642'

您应该注意到,某些转换(如%f)有点棘手。浮点数(带%f)总是在小数点后6位输出,除非指定精度。修饰语(见下文对'.'精度修饰符)。换句话说,将值'2'打印为%f将实际输出为2.000000。这意味着在指定字段宽度时必须考虑到已经添加了7个字符。要使2的值以一个前导零打印,则必须使用9个字段宽度(7为'.'和6个零,1为'2',1为前导零)。

所有其他说明符也以这种方式工作。要找出指定符默认输出多少字符,请输出0(零)的值,并计算有多少字符:
# this outputs: '0, 0.000000, 0.000000e+00'
printf("%d, %f, %e", 0, 0, 0);

也可以让perl帮你计算:
printf("There are %d characters\n", length(sprintf("%e", 0)));

它应该告诉你在科学记数法中0有12个字符。

用空格填充

这或多或少与前导零相似,除了它使用前导(或者,如果被告知后置)空格来完成字段宽度。例如,这对于将多行数据排列到报表中很有用(尽管在这种情况下,可能还希望指定最大字段宽度以截断长值,下面将详细介绍)。语法就像前导零,但省略前导零:
printf("%6s", 'foo');    # prints '   foo'

默认情况下使用前导空格,因此值在其字段中看起来是右对齐的。要扭转这种情况,在字段宽度前加一个'-'号:
printf("%-6s", 'foo');    # prints 'foo   '

对于具有默认精度的数值,如%f和%e,此处的操作与前导零一样。例如,%f不会有任何填充,除非您放置的字段宽度大于8。

精度修饰符

精度修饰符告诉printf()小数点后需要多少位数字,如果它是浮点说明符的话。如果位数多于指定的位数,则将该值舍入。如果小于0,则用0来填充空间。

printf("%.2f", 9.333333);    # prints '9.34'
printf("%.2f", 9);    # prints '9.00'

在v5.32下的测试结果:
printf("%.2f\n", 9.333333);    #9.33
printf("%.1f\n", 9.55);    #9.6
printf("%.1f\n", 43.55);    #43.5

网友解释说:
The first one (9.3333 -> 9.34) is a typo in the original.
The second and third one are easily explained by the following

printf("%.15f", 9.55);   # prints 9.550000000000001
printf("%.15f", 43.55);   # prints 43.549999999999997

这意味着由于内部表示的限制,字面量9.55实际上是9.550000000000001,四舍五入为9.56;43.55也是如此,但它的表示比43.55略小,因此出现了四舍五入。

对于十进制值,精度修饰符与上面描述的'0'修饰符具有相同的效果:
printf("%.3f", 7);    # prints 007

For string values, it has the nice effect of specifying a maximum field width, where it will only print out the first n characters of the string. In combonation with the field width modifier described above, you can have a well-behaved-under-all-circumstances string field.
对于字符串值,它具有指定最大字段宽度的良好效果,它将只打印字符串的前n个字符。结合上面描述的字段宽度修饰符,您可以拥有一个在任何情况下都表现良好的字符串字段。

printf("%.3s", 'foobar');    # prints 'foo'
printf("%.10s", 'foobar');    # prints 'foobar'
printf("%5.5s %5.5s", 'foobar', 'baz');    # prints 'fooba   baz'

使用sprintf进行四舍五入

曾经想要在perl中将浮点数四舍五入为小数吗?或者四舍五入到小数点后任意一位?sprintf()提供了这样做的能力。

# this sets $foo to '3'
$foo = sprintf("%d", 3.14);

# this sets $bar to '7.3531'
$bar = sprintf("%.4f", 7.35309);

%d指定将给定值转换为十进制整数。必要时进行转换轮询。%.4f指定将给定的值转换为精度为小数点后4位的浮点数,根据需要将值四舍五入。
注意这里说的是根据需要,即当时的数据在计算机中的存储方式,比如7.35309在经由上述的转换后却是7.3530。

八进制和十六进制

可以使用printf()和sprintf()将基于十进制的值转换为十六进制和八进制值。为此,请将转换指定为八进制的%o和十六进制的%x。%X等同于%X,只是结果是用大写字母打印的。
printf("%x", 15);    # prints 'f'
printf("%X", 15);    # prints 'F'
printf("%o", 15);    # prints '17'

正如'Format Modifiers'一节中所解释的,在%后面使用'#'将值转换为"alternate form"。对于%x和%x,它将分别添加到值'0x'和'0X'之前。对于%o,添加一个单独的前导'0'(数字零)。使用#修饰符的额外字符被认为是字段宽度的一部分。
printf("%#x", 15);    # prints '0xf'
printf("%#o", 15);    # prints '017'
printf("%#4x", 15);    # prints ' 0xf'

在最后一个示例中,指定字段宽度为4。由于#修饰符为值添加了两个额外的字符,最终总共占用3个字符。因此只有一个前导空格。

科学计数

printf("%e\n", 0);    #0.000000e+00

When to Use, and When Not to
什么时候用,什么时候不用

虽然printf比print更强大,但它的效率也更低,更容易出错。printf手册告诉我们,如果简单的print够用就不要使用printf,这是一个很好的建议。当需要控制printf()提供给的值的格式时,当希望使用字段宽度时(并且不太关心perl的报告),以及当希望对浮点数进行舍入时,应该使用printf。

请求指正

请将任何错误和更正贴在下面。我会谦卑而尴尬地承认我的错误并改正它。非常感谢有帮助的评论。

----------------
文章后的部分评论:

%g same as %e or %f, whichever printf thinks is best.

四舍五入在printf中的表现的差异(浮点数在主机内部的存储方式的区别)

printf("%.2f", 9.333333);
This prints "9.33". Actually, this is what I expect, but the article says it should be 9.34.

If I try the following:printf("%.1f", 9.55);
I get 9.6, which is OK, but if I try printf("%.1f", 43.55);
But get 43.5.

回复如下:
The first one (9.3333 -> 9.34) is a typo in the original.
The second and third one are easily explained by the following:
printf("%.15f", 9.55);    # prints 9.550000000000001
printf("%.15f", 43.55);    # prints 43.549999999999997

这意味着由于内部表示的限制,字面量9.55实际上是9.550000000000001,四舍五入为9.56。43.55也是如此,但它的表示比43.55略小,因此出现了四舍五入。

计算网络段
my $anded = sprintf "%vd\n", 192.168.16.1 & 255.255.248.0;
say '$anded:',$anded;

---------------------------
另类中文参考:
runebook-cn-perl-printx

---------------------------
参考文档
print
printf
sprintf
Using (s)printf()