Boost中包括五个字符串与文本处理领域的程序库:
【1】两个与c标准库函数功能类似的lexical_cast和format,它们关注与字符串的表示,可以将数值转化为字符串,对输出做精确的格式化。
【2】string_algo库提供了大量常用的字符串处理函数
【3】tokenizer和xpressive,前者是一个分词器,后者则是一个灵活的正则表达式分析器,同时也是一个语法分析器.
lexical_cast:
lexical_cast库进行"字面量"的转换,类似c中的atio函数,可以进行字符串,整数/浮点数之间的字面转换。
#include<boost/lexical_cast.hpp>
using namespace boost;
用法:
lexcial_cast使用类似c++98标准转型操作符(xxx_cast)的形式给出了通用,一致,可理解的语法。
使用lexcical_cast可以很容易地在数值与字符串之间转换,只需要在模板参数中指定转换的目标类型即可,示例:
#include <iostream>
#include <boost/lexical_cast.hpp>
using namespace boost;
using namespace std;
int main()
{
int x = lexical_cast<int>("100");
long y = lexical_cast<long>("2000");
float pai = lexical_cast<float>("3.14159e5");
double e = lexical_cast<double>("2.71828");
cout<<x<<","<<y<<","<<pai<<","<<e<<endl;
string str = lexical_cast<string>(456);
cout<<str<<endl;
cout<<lexical_cast<string>(0.618)<<endl;
cout<<lexical_cast<string>(0x10)<<endl;
system("pause");
return 0;
}
注意:要转换成数字的字符串中只能有数字和小数点,不能出现字母(表示指数的e/E除外)或其他非数字字符,也就是说,lexcical_cast不能转换如"123L","0x100"这样的c++语法许可的数字字面量字符串,而且lexcical_cast不支持高级的格式控制,不能把数字转换成指定格式的字符串,如果要更高级的格式控制,可使用std::stringstream或者boost::format;
除了转换数值与字符串,lexcical_cast也可以转换bool类型,但功能很有限,不能使用true/false字面量,只能使用1或0;
cout<<lexical_cast<bool>("1")<<endl;
异常bad_lexical_cast
当lexcical_cast无法执行转换操作时会抛出异常bad_lexical_cast,它是std::bad_cast的派生类,为了使程序更加健壮,使用try/catch块来保护转换代码;
示例:
#include <iostream>
#include <boost/lexical_cast.hpp>
using namespace boost;
using namespace std;
int main()
{
try
{
cout<<lexical_cast<int>("0x100")<<endl;
cout<<lexical_cast<double>("HelloWorld")<<endl;
cout<<lexical_cast<long>("100L")<<endl;
cout<<lexical_cast<bool>("false")<<endl;
}
catch (bad_lexical_cast& e)
{
cout<<"error: "<<e.what()<<endl;
}
system("pause");
return 0;
}
也可以利用bad_lexical_cast来验证数字字符串的合法性,实现一个模板函数num_valid()代码如下:
template<typename T>
bool num_valid(const char *str)
{
try
{
lexical_cast<T>(str);
return true;
}
catch(bad_lexical_cast&)
{
return false;
}
}
int main()
{
assert(num_valid<double>("3.14"));
assert(!num_valid<int>("3.14"));
assert(num_valid<int>("65535"));
system("pause");
return 0;
}
转换对象的要求:
lexical_cast实际是一个模板函数,内部使用了标准库的流操作,因此,对于它的转换对象有如下要求:
【1】转换起点对象是可流输出的,即定义了operator<<;
【2】转换终点对象是可流输入的,即定义了operator>>;
【3】转换终点对象必须是可缺省构造和可拷贝构造的;
c++语言中的内建类型(int,double等)和std::string都满足以上的三个条件;
应用于自己的类:
如果要将lexcical_cast应用于自定义的类,把类转换为可理解的字符串描述,只需要满足lexcical_cast的要求即可,准确地说,需要实现流输出操作符operator<<;
示范:
#include <iostream>
#include <boost/lexical_cast.hpp>
using namespace boost;
using namespace std;
class demo_class
{
friend std::ostream& operator<<(std::ostream& os, const demo_class& x)
{
os<<"demo_class's Name";
return os;
}
};
int main()
{
cout<<lexical_cast<string>(demo_class())<<endl;
system("pause");
return 0;
}
这段代码值得提取一个模板类,可以仿造boost.operator库,定义一个模板类outable,以简化流输出操作符<<重载,注意这里没有使用基类链技术,不能用operator的基类串联;
示例:
#include <iostream>
#include <boost/lexical_cast.hpp>
using namespace boost;
using namespace std;
template<typename T>
struct outable
{
friend std::ostream& operator<<(std::ostream& os, const T &x)
{
os<<typeid(T).name();
return os;
}
};
class demo_class: outable<demo_class>
{};
int main()
{
cout<<lexical_cast<string>(demo_class())<<endl;
system("pause");
return 0;
}
这样任何继承outable的类,都会自动获得流输出操作符<<或者lexcical_cast的支持
依据同样的原理,也可以实现流输入操作符>>的重载.
format:
boost.format可以把参数格式化到一个字符串,而且是完全类型安全的。
#include<boost/format.hpp>
using namespace boost;
简单例子:
#include <assert.h>
#include <iostream>
#include <boost/format.hpp>
using namespace boost;
using namespace std;
int main()
{
cout<<format("%s:%d+%d=%d\n")%"sum"%1%2%(1+2);
format fmt("(%1% + %2%) * %2% = %3%\n");
fmt %2%5;
fmt %((2+5)*5);
cout<<fmt.str();
system("pause");
return 0;
}
输入操作符%:
为什么使用重载操作符:
基于类型安全的考虑,format不能使用省略号来实现可变参数,如果使用函数的调用形式,那么就需要定义不同参数数量的模板函数,如:
template<class T1, class T2, .., class TN>
string format(string s, const T1 &x1, ..., const T1& xN);
在c++没有实现可变数量模板参数之前,无论定义多少个这样的重载形式,都无法满足格式化“无限”个参数的需求,因此,必须使用操作符的方式来接受参数,而且IO流的operator<<已经应用了许多年,证明这种方式的确有效,
二元操作符operator%()声明如下:
format& operator%(T& x);
它接受format对象和任意值作为参数,然后返回format对象的引用,因此可以再对返回的format对象实施%操作符,所以:
format("...")%x%y
被编译器解释为:
operator%(format("..."), x) %y =>
operator%(operator%format("..."), x), y)
依次类推,从而能够接受无限个待格式化的参数。
类摘要:
format并不是一个真正的类,而是一个typedef,真正的实现是basic_format
格式化语法:
format基本继承了printf的格式化语法,仅对printf语法有少量的不兼容;
每个printf格式化选项以%开始,后面是格式规则,规定了输出的对齐,宽度,字符类型:
【1】%05d;输出宽度为5的整数,不足位用0填充
【2】%-8.3f;输出左对齐,总宽度为8,小数位3位的浮点数
【3】%10s;输出10位的字符串,不足位用空格填充
【4】%05X;输出宽度为5的大写16进制整数,不足位用0填充。
在经典的printf式格式化外,format还增加了新的格式:
【5】%|spec|:与printf格式选项功能相同,但两边增加了竖线分隔,可以更好地区分格式化选项与普通字符;
【6】%N%;标记第N个参数,相当于占位符,不带任何其他的格式化选项。
高级用法:
format提供了类似printf的功能,但它并不等同于printf函数,这就是面向对象的好处,在通常的格式化字符串之外,format类还拥有几个高级功能,可以再运行时修改格式化选项,绑定输入参数。
这些高级功能用到的函数如下:
【1】basic_format&bind_arg(int argN, const T& val)
把格式化字符串第argN位置的输入参数固定为val,即使调用clear()也保持不变,除非调用clear_bind()或clear_binds().
【2】basic_format& clear_bind(int argN)
取消格式化字符串第argN位置的参数绑定.
【3】basic_format& clear_binds()
取消格式化字符串所有位置的参数绑定,并调用clear().
【4】basic_format& modify_item(int itemN, T manipulator)
设置格式化字符串第itemN位置的格式化选项,manipulator是一个boost::io::group()返回的对象。
【5】boost::io::group(T1 al, ..., Var const &var)
它是一个模板函数,最大支持10个参数(10个重载形式),可以设置IO流操纵以指定格式或输入参数值,IO流操纵器位于头文件<iomanip>.
示例:
#include <iostream>
#include <boost/format.hpp>
#include <iomanip>
using namespace boost;
using boost::io::group;
using namespace std;
int main()
{
//声明format对象,有三个输入参数,五个格式化选项
format fmt("%1% %2% %3% %2% %1% \n");
cout<<fmt %1 % 2 % 3;
fmt.bind_arg(2, 20); //将第二个输入参数固定为数字20
cout<<fmt %1 %3; //输入其余两个参数
fmt.clear(); //清空缓冲,但绑定的参数不变
//在操作符中使用group(),指定IO流操纵符第一个参数显示为八进制
cout<<fmt % group(showbase, oct, 111) % 333;
fmt.clear_binds(); //清除所有绑定参数
//设置第一个格式化项,十六进制,宽度为8,右对齐,不足位用*填充
fmt.modify_item(1, group(hex, right, showbase, setw(8), setfill('*')));
cout<<fmt % 49 % 20 %100;
system("pause");
return 0;
}