简述
编程中经常会遇到需要到使用的数据进行格式化的地方,如生成记录日志的字符串,生成发送到网络的完整数据等。
可能需要对int, string, char等进行格式化,常用的方法包括 snprintf, std::string, std::stringstream, boost::format等。
snprintf支持c语言,可能是这几种方式中效率最高的,它们之间的效率对比可以参考 Comparing the performance of a sequence of several generators 。
但对于效率要求不是非常严苛的场合下,使用其他方法可能会更加方便,这里就要介绍boost::format。
boost::format使用
如果你已经在使用boost库,使用format进行格式化将是一件非常简单的事情。
如前所述,format没有snprintf快,但它是类型安全的。它使用streams构建输出,所以不会存在内存溢出的情况。
format有两种使用风格,一种类似于 printf,另一种使用占位符,类似于c#。
浮点数格式
直接上代码:
const double almostpi = 22.0 / 7.0;
// Printf
printf("Pi is %f\n", almostpi);
// Boost format with printf syntax
boost::format printf_formatting("Pi is %f\n");
std::cout << printf_formatting % almostpi;
// Boost format with positional syntax
boost::format position_formatting("Pi is %1%\n");
std::cout << position_formatting % almostpi;
// Output:
// Pi is 3.142857
// Pi is 3.142857
// Pi is 3.14286
显然,format的使用与printf类似,使用 %f 格式化一个浮点数,默认的精度是6位小数。
使用更大的数据可以验证这个结论,如:
const double almostpi = 22.0 / 7.0;
const double distancetosun = 149600000000.0; // meters
const double earthorbitlength = 2 * almostpi * distancetosun;
// Printf
printf("Earth orbit distance is %f meters\n", earthorbitlength);
// Boost format with printf syntax
boost::format printf_formatting("Earth orbit distance is %f meters\n");
std::cout << printf_formatting % earthorbitlength;
// Boost format with positional syntax
boost::format position_formatting("Earth orbit distance is %1% meters\n");
std::cout << position_formatting % earthorbitlength;
// Output:
// Earth orbit distance is 940342857142.857180 meters
// Earth orbit distance is 940342857142.857180 meters
// Earth orbit distance is 9.40343e+011 meters
使得 %1% 占位符时,当数值较大时,会使用科学计数法(大概6-7个字符长度时会使用)。
关于科学计数法
一般而言,只有在使用占位符时,且数值较大时才会转换为科学计数法。如:
boost::format scinotation("Do we use scientific? '%1%'\n");// %llu时也会显示科学计数法
for (size_t n=0; n<15; ++n)
{
double value = 1 * pow(10, n) + 0.5;
std::cout << scinotation % value;
}
// Output:
// Do we use scientific? '1.5'
// Do we use scientific? '10.5'
// Do we use scientific? '100.5'
// Do we use scientific? '1000.5'
// Do we use scientific? '10000.5'
// Do we use scientific? '100001'
// Do we use scientific? '1e+006'
// Do we use scientific? '1e+007'
// Do we use scientific? '1e+008'
// Do we use scientific? '1e+009'
// Do we use scientific? '1e+010'
// Do we use scientific? '1e+011'
// Do we use scientific? '1e+012'
// Do we use scientific? '1e+013'
// Do we use scientific? '1e+014'
另外,在实际使用中,如果使用了不匹配的标记符时,如使用了%llu, 而实际数值却是double时,也会以科学计数法显示。
可以使用 %e 显示指定以科学计数法显示。
格式控制
格式控制的语法为:%[N$][flags][width][.precision]type-char
。如:
// Printf
printf("Pi is '%10.2f'\n", almostpi);
// Boost format with printf syntax
boost::format printf_formatting("Pi is '%10.2f'\n");
std::cout << printf_formatting % almostpi;
// Boost format with positional syntax
boost::format position_formatting("Pi is '%1$10.2f'\n");
std::cout << position_formatting % almostpi;
// Output:
// Pi is ' 3.14'
// Pi is ' 3.14'
// Pi is ' 3.14'
常用示例
简单的使用方式,可以直接输出想要的内容:
// 直接输出
cout << boost::format("%s") % "this is what i want" << endl;
// 结合 string
string s;
s = str(boost::format("%s") % "this is what i want");
cout << s << endl;
// 使用 formater
boost::format fmt("%s");
fmt % "this is what i want";
string s = fmt.str();
cout << s << endl;
// 占位符
cout << boost::format("%1%") % "this is what i want" << endl;
异常处理
format 异常时会throw 异常信息,所以要使用try语句块处理异常,否则程序默认会终止。如:
try
{
cout << boost::format("%d%d") % 1 << endl;
}
catch (std::exception const &e)
{
cout << e.what() << endl;
}
catch (...)
{
cout << "format error" << endl;
}
// output
// boost::too_few_args: format-string refered to more arguments than were passed
参考资料:
Boost::format (and wformat) examples – numbers: int, float, double
Comparing the performance of a sequence of several generators
浅尝boost之format