10.3.3字符串格式化
先看一段代码:
#include <iomanip>
printf("\"%d, %4d, %04d\"\n", 11, 12, 13);
cout << '\"' << 11 << "," << setw(4)
<< setw(4) << 12 << "," << setw(4)
<< setfill('0') << 13 << '\n' << endl;
C++标准库的字符串格式化输出控制符,很不容易记忆。并且有的持续有效,有的单次有效。
可以上cppreference.com或cplusplus.com查询,前者文档更佳,后者有不少好例子。
C语言的printf,又有类型不安全的问题。
boost::format提供了两全其美的解决方案:
#include <iostream>
#include <boost/format.hpp>
using namespace std;
void test1()
{
cout << boost::format("I'm %s. I'm %d.") % "Tom" %10 << endl;
}
用法是: 先构造出一个boost::format对象,构造时传入一个“格式符控制串”, 然后用%操作符接收实际的参数
“格式符控制串”,采用和printf基本一致的控制符表示法,比如s%表示这里需要一个字符串,d%表示需要一个整数。
1.类型指示符
格式化类型指示符如表10-2所列。
类型指示符 | 含义 | 备注 |
%c | 一个字符 | char |
%d | 一个整数 | digit |
%u | 一个无符号整数 | unsigned |
%f | 一个浮点数 | float,double |
%e | 采用科学计数法的浮点数 | |
%g | 自动选择 %f 和 %e | 选择比较短的表达法 |
%o | 以八进制显示给定的整数 | oct |
%x | 以十六进制显示给定的整数 | hex,如果是%X,则字母大写 |
%s | 字符串 | 直接支持 std::string |
%p | 指针(一个内存地址) | point,十六进制显示,如果确实是给一个变量的地址,则自动加上0x前缀 |
%% | 输出一个百分号 |
2.常见格式控制符
宽度控制,在类型指示符前面加一个正整数,表示输出宽度,比如:
cout << boost::format("% 10s, % 4d") % "Tom" %123 << endl;
输出结果Tom前面将补充7个空格,123数字前面补充1个空格。如果在宽度指示符前面再加一个0,则不足位补充数字0,而不是空格:
cout << boost::format("% 010s, % 04d") % "Tom" %123 << endl;
也可以控制数字的精度:
cout << boost::format("%8.3f, %3.2f") % 100.2 % 1234.567 << endl;
输出 100.200,1234.57
“%w.p”中,w表示输出总长度,浮点数包含小数点占1位,实际长度不足则如前述补位,实际长度超过,则取实长。p表示精度的表达长度,例子中100.2被输出为100.200,因为精度被指示为最少3为,实际精度不足自动补0,实际精度超过则以“四舍五入”原则截断!
3.简捷输出
为了快速组装不同数据成为一个字符串,boost也支持用户向C#语言学习,不需要指定类型:
cout << boost::format("%1% %2% %3% %1%") % "Hello" % 3 % 29 << endl;
“%N%”表示这里要替换为后面第N个参数,N从1开始(而不是0)。上一行输出代码的输出内容是“Hello 3 29 Hello”,打了两次招呼,是因为格式串中出现了两次“%1%”。
4.构造format对象备用
boost::format是一个类,可以事先构建出一个对象,这对于要整齐划一地输出一批数据,有提高性能的效果:
char const* names [] =
{
"Tom", "Mike", "Mary", "Bill", "Alexander", "Bob"
};
int ages[] = {10, 22, 20, 32, 60, 7};
#define COUNT (sizeof(ages)/sizeof(ages[0]))
boost::format fmt("% 10s ==> %2d");
for(size_t i = 0; i < COUNT; ++ i)
{
/**< boost为format这个类,重载了%操作符 */
cout << fmt %names[i] %ages[i] << endl;
}
这里可以看出,并不是C++为“取余操作符(%)”提供了新的功能,而是boost为format这个类,重载了(%)操作符。
5.format异常
boost::format只要认为当前输出不会出现严重问题(内存越界,指针错指)等,它就会尽量输出,实际输出不了,它还是会抛出异常的,以下是format操作可能抛出的常见异常:
(1)bad_format_string
(2)too_few_args
(3)too_many_args
(4)out_of_range
每个异常的名字都基本做到了自我解释,实际使用时可以统一以它们的共同基类boost::io::format_error来捕获。
#include <boost/format.hpp>
#include <boost/format/exceptions.hpp>
...
try
{
boost::format(...)...;
}
catch(boost::io::format_error const& e)
{
cout << e.what() << endl;
}
6.更高级用法
boost::format还有一些更高级的用法,比如定制宽度补充字符,绑定输入参数等,需自学
最后,如果要处理wstring的格式化,需要采用对应的wformat类。