boost的字符串處理函數——format


用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(const char* format, …)

需要定義三個重載版本:

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

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

    template<class TFirst, class... TOther>
    string string_format(const char* 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"));

所有的異常也都會在該函數中拋出,雖然效率上相對低點,但用起來要舒服點。

PS:可變參數模板的特性在vc 2012中還不支持,不過微軟已經發布了一個CTP版本的編譯器使得可以在vc 2012中使用該特性,應該在下個update版本或sp1中就會正式支持。gcc可以完美支持,windows下也可以通過MinGW使用該特性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM