如何使用 printf 格式化输出

了解 printf,一个神秘、灵活且功能丰富的 echo、print 和 cout 的替代方案。
53 位读者喜欢这篇文章。

当我开始学习 Unix 时,我很快就接触到了 echo 命令。 同样,我的第一个 Python 课程涉及 print 函数。 学习 C++ 和 Java 让我接触到了 coutsystemout。 似乎每种语言都自豪地拥有一种方便的单行输出方法,并像过时了一样宣传它。

但一旦我翻开中级课程的第一页,我就遇到了 printf,一个神秘、令人费解且出奇灵活的函数。 本文旨在打破向初学者隐藏 printf 的令人费解的传统,向世界介绍不起眼的 printf 函数,并解释它如何在几乎任何语言中使用。

printf 的简史

术语 printf 代表 “print formatted”(格式化打印),可能最早出现在 Algol 68 编程语言中。 自从包含在 C 语言中以来,printf 已经在 C++、Java、Bash、PHP 中重新实现,并且很可能在您最喜欢的(C 之后)的语言中实现。

它显然很受欢迎,但与 echoprintcout 等替代方案相比,许多人似乎认为它的语法很复杂。 例如,这是 Bash 中的一个简单的 echo 语句

$ echo hello
hello
$

这是在 Bash 中使用 printf 获得的相同结果

$ printf "%s\n" hello
hello
$

但是,对于增加的复杂性,您可以获得很多功能,这正是 printf 值得学习的原因。

printf 输出

printf 背后的主要概念是它能够根据与内容分离的样式信息来格式化其输出。 例如,printf 识别为特殊字符的特殊序列集合。 您喜欢的语言可能具有更多或更少的序列,但常见的序列包括

  • \n: 新行
  • \r: 回车
  • \t: 水平制表符
  • \NNN: 具有八进制值(包含一到三位数字)的特定字节

例如

$ printf "\t\123\105\124\110\n"
     SETH
$

在此 Bash 示例中,printf 呈现一个制表符,后跟分配给四个八进制值字符串的 ASCII 字符。 以控制序列结束以产生新行 (\n)。

尝试使用 echo 做同样的事情会产生更字面的结果

$ echo "\t\123\105\124\110\n"
\t\123\105\124\110\n
$

使用 Python 的 print 函数执行相同的任务表明 Python 的 print 命令比您想象的要多

>>> print("\t\123\n")
        S

>>>

显然,Python 的 print 结合了传统的 printf 功能以及简单的 echocout 的功能。

不过,这些示例只包含文字字符,虽然它们在某些情况下很有用,但它们可能是 printf 中最不重要的部分。 printf 的真正力量在于格式规范。

使用 printf 格式化输出

格式说明符是以百分号 (%) 开头的字符。

常见的包括

  • %s: 字符串
  • %d: 数字
  • %f: 浮点数
  • %o: 八进制数

这些是 printf 语句中的占位符,您可以用您在 printf 语句中的其他地方提供的值替换它们。 这些值的提供位置取决于您使用的语言及其语法,但这是一个 Java 中的简单示例

string var="hello\n";
system.out.printf("%s", var);

将其包装在适当的样板代码中并执行,将呈现

$ ./example
hello
$

不过,当变量的内容发生变化时,它会变得更加有趣。 假设您想根据不断增加的数字更新您的输出

#include <stdio.h>

int main() {
  int var=0;
  while ( var < 100) {
    var++;
  printf("Processing is %d%% finished.\n", var);
  }
  return 0;
}

编译并运行

Processing is 1% finished.
[...]
Processing is 100% finished.

请注意,代码中的双 %% 会解析为单个打印的 % 符号。

使用 printf 限制小数位数

数字可能会变得复杂,并且 printf 提供了许多格式化选项。 您可以使用 %f 限制打印多少小数位,用于浮点数。 通过在百分号和 f 之间放置一个点 (.) 以及一个限制器数字,您可以告诉 printf 呈现多少个小数位。 这是一个用 Bash 编写的简单示例,为了简洁起见

$ printf "%.2f\n" 3.141519
3.14
$

类似的语法适用于其他语言。 这是一个 C 语言中的示例

#include <math.h>
#include <stdio.h>

int main() {
  fprintf(stdout, "%.2f\n", 4 * atan(1.0));
  return 0;
}

对于三位小数,请使用 .3f,依此类推。

使用 printf 向数字添加逗号

由于大数字可能难以解析,因此通常使用逗号将其分隔开。 您可以通过在百分号和 d 之间放置一个撇号 (') 来让 printf 根据需要添加逗号

$ printf "%'d\n" 1024
1,024
$ printf "%'d\n" 1024601
1,024,601
$

使用 printf 添加前导零

printf 的另一个常见用途是在文件名上强制实施特定格式。 例如,如果您在计算机上有 10 个顺序文件,计算机可能会在 1.jpg 之前对 10.jpg 进行排序,这可能不是您的意图。 以编程方式写入文件时,您可以使用 printf 以带有前导零字符的文件名形成文件名。 这是一个用 Bash 编写的简单示例,为了简洁起见

$ printf "%03d.jpg\n" {1..10}
001.jpg
002.jpg
[...]
010.jpg

请注意,每个数字最多使用 3 位。

使用 printf

正如您可以从这些 printf 示例中看出的那样,包括控制字符,尤其是 \n,可能很乏味,并且语法相对复杂。 这就是开发诸如 echocout 之类的快捷方式的原因。 但是,如果您时不时地使用 printf,您会习惯该语法,并且它将成为第二天性。 我看不到任何理由 printf 应该是您在日常活动中打印语句的首选,但它是当您需要它时,可以足够舒适地使用而不会让您慢下来的绝佳工具。

花一些时间学习您选择的语言中的 printf,并在需要时使用它。 这是一个强大的工具,您不会后悔拥有它。

接下来读什么
标签
Seth Kenlon
Seth Kenlon 是一位 UNIX 极客、自由文化倡导者、独立多媒体艺术家和 D&D 爱好者。 他曾在电影和计算机行业工作,而且经常同时从事这两项工作。

2 条评论

您使用 000%d 来左填充文件名是完全错误的。 您的格式字符串应该是 %03d

你说得完全正确。 我已经在文章中对其进行了更正,以供后人参考。

回复 作者:Chris Elvidge (未验证)

Creative Commons License本作品采用知识共享署名 - 相同方式共享 4.0 国际许可协议进行许可。
© . All rights reserved.