boost的字符串处理函数——format

时间:2022-09-09 00:00:40

来源:http://www.cnblogs.com/TianFang/archive/2013/02/04/2891501.html


boost::format的格式一般为:
    boost::format( "format-string ") % arg1 % arg2 % ... % argN ;
    注意这里没有示例对象,format-string代表需要格式化的字符串,后面用重载过的%跟参数

1.format占位符的使用 (占位符 是 从 1 开始的,不是从 0 开始的)
    std::cout<<boost::format("%1% \n %2% \n %3%" )%"first"%"second"%"third";
    上面例子中%X%表示占位符,%1%就是第一个占位符,%2%就是第二个,后面类推,
    再后面的%"xxx"就对应着每个占位符,也就是说如果我们写成:
    std::cout<<boost::format("%2% \n %1% \n %3%" )%"first"%"second"%"third";

    将会输出
    second
    first
    third

    当然我们也可以分开写,比如:
    boost::format fmt("%2% \n %1% \n %3%" );
    fmt %"first";
    fmt %"second";
    fmt %"third";

2.format的C语言形式
    你可以这样通过变量格式化,这与int a=5;printf("%d",a);是一个道理,不同的是format是对字符的格式化而不包含输出。
    int a=5;
    int b=6;
    std::cout<< boost::format("%1% %2%" )%a%b;

// 方式一 
cout << boost::format("%s") % "输出内容" << endl;

// 方式二
std::string s;
s = str( boost::format("%s") % "输出内容" );
cout << s << endl;

// 方式三
boost::format formater("%s");
formater % "输出内容";
std::string s = formater.str();
cout << s << endl;

// 方式四
cout << boost::format("%1%") % boost::io::group(hex, showbase, 40) << endl;
/*        三、boost::format新的格式说明符            %{nt}            当n是正数时,插入n个绝对制表符            cout << boost::format("[t]")  << endl;            %{nTX}            使用X做为填充字符代替当前流的填充字符(一般缺省是一个空格)            cout << boost::format("[T*]")  << endl;    */    cout<<boost::format("[%5t] Test %5t* ");
#include <iostream>#include <string>#include <vector>#include <set>#include <map>#include <algorithm>#include <boost/format.hpp>#include <iomanip>using namespace boost;using namespace std;using boost::io::group;/*format类摘要namespace boost {template<class charT, class Traits=std::char_traits<charT> > class basic_format {public:  typedef std::basic_string<charT, Traits> string_t;  typedef typename string_t::size_type     size_type;  basic_format(const charT* str);  basic_format(const charT* str, const std::locale & loc);  basic_format(const string_t& s);  basic_format(const string_t& s, const std::locale & loc);  basic_format& operator= (const basic_format& x);  void clear(); // reset buffers  basic_format& parse(const string_t&); // clears and parse a new format string  string_t str() const;  size_type size() const;  // pass arguments through those operators :  template<class T>  basic_format&   operator%(T& x);    template<class T>  basic_format&   operator%(const T& x);  // dump buffers to ostream :  friend std::basic_ostream<charT, Traits>&   operator<< <> ( std::basic_ostream<charT, Traits>& , basic_format& );    // Choosing which errors will throw exceptions :   unsigned char exceptions() const;   unsigned char exceptions(unsigned char newexcept);// ............  this is just an extract .......}; // basic_formattypedef basic_format<char >          format;typedef basic_format<wchar_t >      wformat;// free function for ease of use :template<class charT, class Traits> std::basic_string<charT,Traits>  str(const basic_format<charT,Traits>& f) {      return f.str();}} // namespace boost*//*格式化语法: * 1.%05d:输出宽度为5的整数,不足位用0填充 * 2.%-8.3f:输出左对齐,总宽度为8,小数位3位的浮点数 * 3.%10s:输出10位的字符串,不足位用空格填充 * 4.%05x:输出宽度为5的大写16进制数,不足位用0填充 * 5.%|spec|:与printf格式选项功能相同,但两边增加了竖线分隔,可以更好地区分格式化选项与普通字符 * 6.%N%:标记第N个参数,相当于占位符,不带任何奇特的格式化选项 * * 建议: * 1.format由于要做安全检查工作,性能略差,约比printf慢2到5倍,为了提高format的性能,建议在编程中应该先建立const format对象,然后拷贝这个对象进行格式化操作 * * 高级功能: * 1.basic_format& bind_arg(int argN,const T& val); //将第argN个参数绑定为val,即使调用clear()也保持不变 * 2.basic_format& clear_bind(int argN);    //取消格式化字符串第argN位置的参数绑定 * 3.basic_format& clear_binds();   //取消格式化字符串所有位置参数绑定,并调用argN * 4.basic_format& modify_item(int itemN,T manipulator);    //设置格式化字符串第itemN位置的格式化选项,manipulator是一个boost::io::group返回的对象 * */int main( int argc,char **argv){    cout << format("%s:%d+%d=%d\n")%"sum"% 1%2%(1+2); //经典用法    cout << format("%1% %2%") % 36 %37; //简单风格,可以重新排列输出    cout << format("(x,y)=(%1$+5d,%2$+5d)\n") %-23 %35;    //精确的格式化,带posix_printf位置提示符    format fmt("(%1%+%2%)*%2%=%3%");    fmt % 2 % 5;    fmt % ((2+5*5));    format fmt1("%05d\n%-8.3f\n%10s\n%05x\n");    cout << fmt1 %62 %2.236 %" 12345678" %48;    cout << fmt.str() << endl;    format fmt2("%1% %2% %3% %2% %1%\n");    cout << fmt2 %1 %2 %3;    fmt2.bind_arg(2,10);    cout << fmt2 %1 %3;    fmt2.clear();    cout << fmt2 % group(showbase,oct,111) % 333;    fmt2.clear_binds();    fmt2.modify_item(1,group(hex,right,showbase,setw(8),setfill('*')));    cout << fmt2 %49 %20 %100;     return (0);}
// 可以延迟使用,顺序不必一致    boost::format fmter("%2% %1%");    fmter % 36;    fmter % 77;    cout << fmter << endl;    // 输出:77 36       // 可重用    fmter % 12;    fmter % 24;    cout << fmter << endl;    // 输出:24 12     // 可直接转成字符串    std::string s = fmter.str();    std::string s2 = str( boost::format("%2% %1% %2% %1%")%"World"%"Hello");     cout << s << endl << s2 << endl;    // 输出:    // 24 12    // Hello World Hello World     // 可以使用printf指示符    cout << boost::format("%3.1f - %.2f%%") % 10.0 % 12.5  << endl;    // 输出:10.0 - 12.50%     // printf指示符里使用N$指定使用第几个参数    cout << boost::format("%2$3.1f - %1$.2f%%") % 10.0 % 12.5  << endl;    // 输出:12.5 - 10.00%

    std::cout << boost::format("%s:%04d%02d%02d") % "日期"% 2013 % 9 % 28 << std::endl;
std::string test("string");
std::cout << boost::format("%s") % test<< std::endl;

boost::format fmt1("%1% + %2%*%1% = %3%");
fmt1 % 2 % 3 % (2+2*3) ;
std::cout << fmt1.str() << std::endl;

cout << boost::format( "%1% %2%" ) % "Hell" % "Low" << endl;
string s1 = boost::str( boost::format( "%2% %1%" ) % "Hell" % "Low" );
cout << s1 << endl;
wcout << boost::wformat( L"%s %X" ) % L"-1 is" % -1 << endl;
wstring s2 = boost::str( boost::wformat( L"%2$s %1$.2f" ) % 3.141592 % L"Version" );
wcout << s2 << endl;

char text[]="hello";
bool is_all_lower = boost::algorithm::all(text, boost::algorithm::is_lower());

char output[128];
sprintf(output, "<%s> %s in the lower case", text, (is_all_lower? "is": "is not"));
cout<<output<<endl;

用boost::format来格式化字符串

在字符串处理中少不了格式化字符串,C++中传统的格式化函数是C语言的sprintf,但它一个很大的问题就是不安全。因此,在stl中引入了stringstream来实现安全格式化,但是stringstream却远不如sprintf来得直观。例如,对如如下代码:

 char text[]="hello";    
bool is_all_lower = boost::algorithm::all(text, is_lower());

char output[128];
sprintf(output, "<%s> %s in the lower case", text, (is_all_lower? "is": "is not"));
如果把最后两句format的函数用stringstream来写的话,可读性是远不如sprintf的。
stringstream output;
output << "<" << text << "> "<< (is_all_lower)? "is": "is not")<< " in the lower case";
boost引入了一个提供类似.net中的string.format的方式提供格式化字符串的函数,用它来格式化的话就是如下形式:
boost::format fmt = boost::format("<%s> %s in the lower case") % text % (is_all_lower? "is": "is not");
string output = fmt.str();

前面的例子中演示的是C风格的格式化字符串,boost.format也提供了类似.net风格的格式化字符串方式:

    boost::format fmt = boost::format("<%1%>%2% in the lower case") % text % (is_all_lower?"is":"is not");
    cout << fmt << endl;

这种方式更容易看到参数在格式化字符串中的位置,推荐这种形式。不过它的起始坐标是1而不是0,用惯了.net的string.format的朋友需要注意下。

格式化控制

格式化语法为: [ N$ ] [ flags ] [ width ] [ . precision ] type-char。也提供了C语言和.net两种风格。

    //传统c语言风格
    cout << boost::format("\n\n%s"
            "%1t
十进制
= [%d]\n"
            "%1t
格式化的十进制 = [%5d]\n"
            "%1t
格式化十进制,前补'0' = [%05d]\n"
            "%1t
十六进制 = [%x]\n"
            "%1t
八进制 = [%o]\n"
            "%1t
浮点 = [%f]\n"
            "%1t
格式化的浮点 = [%3.3f]\n"
            "%1t
科学计数 = [%e]\n"
            ) % "example :\n" % 15 % 15 % 15 % 15 % 15 % 15.01 % 15.01 % 15.01 << endl;

    //.net
的风格

    cout << boost::format("%1%"
            "%1t
十进制
= [%2$d]\n"
            "%1t
格式化的十进制 = [%2$5d]\n"
            "%1t
格式化十进制,前补'0' = [%2$05d]\n"
            "%1t
十六进制 = [%2$x]\n"
            "%1t
八进制 = [%2$o]\n"
            "%1t
浮点 = [%3$f]\n"
            "%1t
格式化的浮点 = [%3$3.3f]\n"
            "%1t
科学计数 = [%3$e]\n"
            ) % "example :\n" % 15 % 15.01 << endl;

异常处理

既然boost.format函数是用来代替sprintf的,那么自然就得有异常处理的功能,而不是像sprintf那样死给你看。boost.format的处理方法是抛异常,它在如下两种情况家会抛异常:

  1. format字符串非法
  2. format绑定非法

如下代码演示了这两种情形:

try
{
boost::format("<%3");
}
catch(std::exception& err)
{
cout << err.what() << endl;
}

boost::format fmt = boost::format("<%3%> %2% in the lower case") % text % (is_all_lower? "is": "is not");
try
{
cout << fmt << endl;
}
catch(std::exception& err)
{
cout << err.what() << endl;
}

封装

boost.format是以一个对象,而不是函数来实现的,导致其使用和异常处理起来要麻烦不少,不过,利用c++11的可变参数模板的语法还是可以很容易把它封装成一个可变参数的函数的形式:

    string string_fromat(constchar*format, …)

需要定义三个重载版本:

    template<classTFirst>
    void string_format(boost::format&fmt,TFirst&& first)
    {
        fmt % first;
    }

    template<classTFirst,class...TOther>
    void string_format(boost::format&fmt,TFirst&& first,TOther&&...other)
    {
        fmt % first;
        string_format(fmt, other...);
    }

    template<classTFirst,class...TOther>
    string string_format(constchar*format,TFirst&& first,TOther&&...other)
    {
        boost::format fmt(format);
        string_format(fmt, first,other...);
        return fmt.str();
    }

现在就可以这么用了:

    auto output = string_format("<%1%> %2% in the lower case", text, (is_all_lower? "is":"is not"));

所有的异常也都会在该函数中抛出,虽然效率上相对低点,但用起来要舒服点。