boost::format 控制格式化输出 和CString::Format类似

 std::string是个很不错的东东,但实际使用时基本在每个程序里都会遇到不愉快的事情:格式化字符串。我甚至由于这个原因在代码里引入平台有关的MFC,ATL等本来不需要在项目中使用的一些重量级的框架,就为了能轻松的做格式化字符串 :-) 。曾尝试过将ATL::CString的format函数提取出来使用,但ATL::CString的底层调用了windows独有函数,无法跨越平台。当然,现在有了boost::format,我们不用再担心了。boost::format重载了'%'操作符,通过多次调用'%'操作符就能将参数非常方便格式化成字符串,并实现了ATL::CString和C#中的string两者的格式化字符串功能。除了语法刚开始感觉到怪异,功能足以让人感觉到兴奋! 

一、boost::format工作的方式 
  
 基本的语法,boost::format( format-string ) % arg1 % arg2 % ... % argN 
  
 下面的例子说明boost::format简单的工作方式  
   
 

//  方式一 
 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实际使用的实例 
  
 格式化语法: [ N$ ] [ flags ] [ width ] [ . precision ] type-char  
   
 

//  ATL::CString风格 
 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; 
 
  //  C#::string风格 
 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; 
 
 
输出结果 
/* 
example : 
 十进制 = [15] 
 格式化的十进制 = [ 15] 
 格式化十进制,前补'0' = [00015] 
 十六进制 = [f] 
 八进制 = [17] 
 浮点 = [15.010000] 
 格式化的浮点 = [15.010] 
 科学计数 = [1.501000e+001] 
*/
 


三、boost::format新的格式说明符 
  
 %{nt} 
 当n是正数时,插入n个绝对制表符 
 cout << boost::format("[%10t]")  << endl; 
  
 %{nTX} 
 使用X做为填充字符代替当前流的填充字符(一般缺省是一个空格) 
 cout << boost::format("[%10T*]")  << endl;  

四、异常处理 

 一般写法: 

  try 
 
 cout << boost::format("%d%d") % 1 << endl; 
 }
 
  catch(std::exception  const & e) 
 
 cout << e.what() << endl; 
 
 // 输出内容: 
 
// boost::too_few_args: format-string refered to more arguments than were passed 
 }
 


 boost::format的文档中有选择处理异常的办法,不过个人感觉实用性可能不强,下面是文档中的例子  
  

  //  boost::io::all_error_bits selects all errors 
 
//  boost::io::too_many_args_bit selects errors due to passing too many arguments. 
 
//  boost::io::too_few_args_bit selects errors due to asking for the srting result before all arguments are passed 
 
 boost::format my_fmt( const std:: string & f_string) 
 
 using namespace boost::io; 
 format fmter(f_string); 
 fmter.exceptions( all_error_bits ^ ( too_many_args_bit | too_few_args_bit ) ); 
 return fmter; 
 }
 
 cout << my_fmt(" %1% %2% \n") % 1 % 2 % 3 % 4 % 5;
#include <iostream>
#include <iomanip>
#include "boost/format.hpp"

#if !(BOOST_WORKAROUND(__GNUC__, < 3) && defined(__STL_CONFIG_H) )
// not for broken gcc stdlib
#include <boost/io/ios_state.hpp>

#else
// not as complete, but compatible with gcc-2.95 :

void copyfmt(ios& left, const ios& right) {
    left.fill(right.fill());
    left.flags(right.flags() );
    left.exceptions(right.exceptions());
    left.width(right.width());
    left.precision(right.precision());
}

namespace boost {namespace io {
        class ios_all_saver {
            std::basic_ios<char> ios_;
            std::ios & target_r;
        public:
            ios_all_saver(std::ios& right) : ios_(0), target_r(right) {
                copyfmt(ios_, right);
            }
            ~ios_all_saver() {
                copyfmt(target_r, ios_);
            }
        };

    }} // N.S. boost::io


// define showpos and noshowpos :
class ShowPos {
public:
    bool showpos_;
    ShowPos(bool v) : showpos_(v) {}
};
std::ostream& operator<<(std::ostream& os, const ShowPos& x) {
    if(x.showpos_)
    os.setf(ios_base:: showpos);
    else
    os.unsetf(ios_base:: showpos);
    return os;
}
ShowPos noshowpos(false);
ShowPos showpos(true);

#endif // -end gcc-2.95 workarounds

//---------------------------------------------------------------------------//
//  *** an exemple of UDT : a Rational class ****
class Rational {
public:
    Rational(int n, unsigned int d) :
        n_(n), d_(d) {
    }
    Rational(int n, int d); // convert denominator to unsigned
    friend std::ostream& operator<<(std::ostream&, const Rational&);
private:
    int n_; // numerator
    unsigned int d_; // denominator
};

Rational::Rational(int n, int d) :
    n_(n) {
    if (d < 0) {
        n_ = -n_;
        d = -d;
    } // make the denominator always non-negative.
    d_ = static_cast<unsigned int> (d);
}

std::ostream& operator<<(std::ostream& os, const Rational& r) {
    using namespace std;
    streamsize n, s1, s2, s3;
    streamsize w = os.width(0); // width has to be zeroed before saving state.
    //  boost::io::ios_all_saver  bia_saver (os);

    boost::io::basic_oaltstringstream<char> oss;
    oss.copyfmt(os);
    oss << r.n_;
    s1 = oss.size();
    oss << "/" << noshowpos; // a rational number needs only one sign !
    s2 = oss.size();
    oss << r.d_;
    s3 = oss.size();

    n = w - s3;
    if (n <= 0) {
        os.write(oss.begin(), oss.size());
    } else if (os.flags() & std::ios_base::internal) {
        std::streamsize n1 = w / 2, n2 = w - n1, t;
        t = (s3 - s1) - n2; // is 2d part '/nnn' bigger than 1/2 w ?
        if (t > 0) {
            n1 = w - (s3 - s1); // put all paddings on first part.
            n2 = 0; // minimal width (s3-s2)
        } else {
            n2 -= s2 - s1; // adjust for '/',   n2 is still w/2.
        }
        os << setw(n1) << r.n_ << "/" << noshowpos << setw(n2) << r.d_;
    } else {
        if (!(os.flags() & std::ios_base::left)) {
            // -> right align. (right bit is set, or no bit is set)
            os << string(n, ' ');
        }
        os.write(oss.begin(), s3);
        if (os.flags() & std::ios_base::left) {
            os << string(n, ' ');
        }
    }

    return os;
}

int main() {
    using namespace std;
    using boost::format;
    using boost::io::group;
    using boost::io::str;
    string s;

    Rational r(16, 9);

    cout << "bonjour ! " << endl;

    cout << r << endl;
    //          prints : "16/9"

    cout << showpos << r << ", " << 5 << endl;
    //          prints : "+16/9, +5"

    cout << format("%02d : [%0+9d] \n") % 1 % r;

    cout << format("%02d : [%_+9d] \n") % 2 % Rational(9, 160);

    cout << format("%02d : [%_+9d] \n") % 3 % r;

    cout << format("%02d : [%_9d] \n") % 4 % Rational(8, 1234);

    cout << format("%02d : [%_9d] \n") % 5 % Rational(1234, 8);

    cout << format("%02d : [%09d] \n") % 6 % Rational(8, 1234);

    cout << format("%02d : [%0+9d] \n") % 7 % Rational(1234, 8);

    cout << format("%02d : [%0+9d] \n") % 8 % Rational(7, 12345);

    /* output :
     bonjour !
     16/9
     +16/9, +5
     01 : [+016/0009]
     02 : [+  9/ 160]
     03 : [+ 16/   9]
     04 : [   8/1234]
     05 : [1234/   8]
     06 : [0008/1234]
     07 : [+1234/008]
     08 : [+07/12345]
     */

    cerr << "\n\nEverything went OK, exiting. \n";
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值