使用C++输出运算符打印前导零?

81

如何在C++中格式化输出?换句话说,如何用C++实现类似于使用 printf 这样的输出格式:

printf("%05d", zipCode);
我知道我可以在C++中使用printf,但我更喜欢使用输出运算符<<
你会只使用以下代码吗?
std::cout << "ZIP code: " << sprintf("%05d", zipCode) << std::endl;
6个回答

117
这样做可以解决问题,至少对于非负数(a),比如你问题中提到的邮政编码(b)
#include <iostream>
#include <iomanip>

using namespace std;
cout << setw(5) << setfill('0') << zipCode << endl;

// or use this if you don't like 'using namespace std;'
std::cout << std::setw(5) << std::setfill('0') << zipCode << std::endl;

控制填充的最常见IO操作符包括:

  • std::setw(width) 设置字段的宽度。
  • std::setfill(fillchar) 设置填充字符。
  • std::setiosflags(align) 设置对齐方式,其中 align 是 ios::left 或 ios::right。

如果您倾向于使用<<,我强烈建议您了解 fmt 库(请参见https://github.com/fmtlib/fmt)。这是我们格式化工具包的重要组成部分,比大量长度的流管道更加方便,让您可以执行如下操作:

cout << fmt::format("{:05d}", zipCode);

目前,LEWG正在将其定位为C++20的一部分,这意味着它有望成为该语言的基础部分(如果没有被纳入,则几乎肯定会在稍后实现)。


(a) 如果您需要处理负数,可以按以下方式使用std::internal

cout << internal << setw(5) << setfill('0') << zipCode << endl;

这将把填充字符放置在符号和数量之间。


(b) 这个(“所有邮政编码都是非负数”)是我自己的假设,但我敢保证是相当安全的 :-)


2
请注意,您也可以只使用 cout << leftcout << right 进行对齐。 - Dan Moulding
请注意,此解决方案对负数无效!尝试以此方式打印“-5”会导致输出“000-5”。 - Nadav Har'El
添加 std::internal 将使得这段代码对于负数的处理正确。 - Nadav Har'El
2
@Nadav,你住在有负数邮政编码的地区吗? :-) 更严肃的话题是,我会编辑答案以澄清这一点。 - paxdiablo
1
谢谢。我实际上是在寻找适用于任何整数(包括负数)的通用解决方案时发现了您的不错且排名很高的答案,但我没有意识到因为提到了邮政编码,该答案假定整数为正数。感谢您编辑答案,这可能会帮助更多人在未来解决问题。 - Nadav Har'El

15

在C++20中,你可以这样做:

std::cout << std::format("{:05}", zipCode);

在旧系统上,您可以使用{{link1:{fmt}库}},std::format基于此。

免责声明:我是{fmt}和C++20 std::format的作者。


更多信息请参见:https://dev59.com/PHE95IYBdhLWcg3wXcvd#57286312 - Ciro Santilli OurBigBook.com

14

使用 setw 和 setfill 函数:

std::cout << std::setw(5) << std::setfill('0') << zipCode << std::endl;

重新激活并+1,因为它展示了如何在任何命名空间中实现(还添加了setfill、sqook,希望您不介意)。 - paxdiablo
好的。 "using namespace std;" 绝对是有害的。 ;) - Nik Reiman
1
我认为这个答案应该提到,与std::setw的设置不同,std::setfill的设置将在输出执行后保持不变,换句话说,std::cout的填充字符将永久更改(直到被另一个std::setfill修改)。由于这不太可能是理想的,因此最好保存和恢复先前的填充字符。 - Marc van Leeuwen

5

2
或者,
char t[32];
sprintf_s(t, "%05d", 1);

会输出00001,正如操作员已经想要的那样。

4
楼主明确要求使用 << 操作符而不是 (s)printf 的方法。 - jankes
@jankes 那就是:std::cout << "邮政编码:" << sprintf_s(t,"%05d",1) << endl; - Mohamed ElNakeep

0

简单的答案,但它有效!

ostream &operator<<(ostream &os, const Clock &c){
// format the output - if single digit, then needs to be padded with a 0
int hours = c.getHour();

// if hour is 1 digit, then pad with a 0, otherwise just print the hour
(hours < 10) ? os << '0' << hours : os << hours;

return os; // return the stream
}

我正在使用三元操作符,但它可以翻译为if/else语句,如下所示

if(c.hour < 10){
 os << '0' << hours;
}
 else{
  os  << hours;
 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接