一起學習Boost標準庫--Boost.texical_cast&format庫

今天接續介紹有關字符串表示相關的兩個boost庫:

  • lexical_cast 將數值轉換成字符串
  • format 字符串輸出格式化

首先,介紹下lexical_cast ,聞其名,知其意。類似C中的atoi 函數,可以進行字符串與整數/浮點數之間的字面轉換

Boost::lexical_cast庫

前期準備

lexical_cast庫位於boost命名空間下,使用需要引入頭文件

#include <boost/lexical_cast.hpp>
using namespace boost;

函數聲明

lexical_cast使用類似C++標類型操作符的形式進行通用的語法,其聲明如下:

// 1. 標準形式,轉換數字和字符串
template <typename Target, typename Source>
inline Target lexical_cast(const Source &arg);

// 2. 轉換C字符串
template <typename Target>
inline Target lexical_cast(const char* chars, std::size_t count);
inline Target lexical_cast(const unsigned char* chars, std::size_t count);
inline Target lexical_cast(const signed char* chars, std::size_t count);
inline Target lexical_cast(const wchar_t* chars, std::size_t count);
inline Target lexical_cast(const char16_t* chars, std::size_t count);
inline Target lexical_cast(const char32_t* chars, std::size_t count);
  • 第一種形式有兩個模版參數,Target 爲需要轉換的目標類型,通常是數字類型或者std::string,第二個參數Source 則不用寫,可以通過函數參數推到出來,調用形式如下
lexical_cast<int>("123");
lexical_cast<double>("234.123");
lexical_cast<std::string>(567.789);
  • 第二種形式主要用來處理C字符串,支持多種類型,只接受一個模板參數Target,指明轉換後的目標類型,函數參數charscount 則標記了要轉換的字符串範圍
const char* double_str = "123.456";
double d1 = lexical_cast<double>(double_str, strlen(double_str));

使用樣例

通過上文的介紹,您大概已經知道如何使用了,此處,我們就通過一個簡單Demo來使用lexical_cast庫

#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
using namespace boost;

int main()
{
    int age = lexical_cast<int>("29");
    int money = lexical_cast<long>("10000000");
    float pai_f = lexical_cast<float>("3.1415926535");
    double pai_d = lexical_cast<double>("3.14159265358979323846264338324990", 20);

    cout << "age: " << age << endl
        << "money: " << money << endl
        << setiosflags(ios::fixed)
        << "pai_f: " << setprecision(8) << pai_f << endl
        << "pai_d: " << setprecision(16) << pai_d << endl;


    cout << lexical_cast<string>(age) << endl
        << lexical_cast<string>(money) << endl
        << lexical_cast<string>(pai_d) << endl;

    return 0;
}

Output:

age: 29
money: 10000000
pai_f: 3.14159274
pai_d: 3.1415926535897931
29
10000000
3.1415926535897931

注意: 使用lexical_cast時要注意,轉換成數字的字符串中只能有數字和小數點,不能出現字母或其他非數字字符,同時也不支持高級的格式控制,如果要進行復雜的格式控制可以使用std::stringstramboost::format (後面介紹該庫)

錯誤處理

當lexcial_cast無法執行轉換操作的時候會拋出異常bad_lexical_cast ,他是std::bad_cast 的派生類,此處以上文中注意 來說明

    try
    {
        int age = lexical_cast<int>("0x64");
        //int age = lexical_cast<int>("100L");
        //bool f = lexical_cast<bool>("false");
        cout << "age: " << age << endl;
    }
    catch (bad_lexical_cast &e)
    {
        cout << "cast error: " << e.what() << endl;
    }

Output:

cast error: bad lexical cast: source type value could not be interpreted as target

如果每次都通過異常捕獲來處理,就比較麻煩了,還好lexical_cast爲我們想到了,再命名空間boost::conversion 提供方法try_lexical_convert() 函數來避免拋出異常,通過返回bool值來表示是否轉換成功。具體使用如下:

using namespace boost::conversion;
int x = 0;
if (!try_lexical_convert<int>("0x64", x))
    cout << "convert failed" << endl;
else
    cout << "x: " << x << endl;

Boost.format庫

C++標準庫提供了強大的輸入輸出流處理,可以通過設置輸出各種各樣的格式,精度控制、填充、對齊等。但是唯一缺點就是太複雜了,真心記不住這麼多,還是懷戀printf() 可以通過規定的樣式輸出想要的格式。雖然C++中可以繼續使用printf() 但它缺乏類型安全檢查等其他缺點,重點就是boost.format庫實現了類似於printf() 的格式化對象,可以把參數格式化到一個字符串,而且是類型安全的,是一個header-only 的函數庫,只要準備好頭文件,不用預先編譯就可以使用了,最主要的是用着還挺順手。

前期準備

format庫位於boost命名空間中,需引入頭文件:

#include <boost/format.hpp>
using namespace boost;

類聲明

template <class Ch, 
        class Tr = BOOST_IO_STD char_traits<Ch>, class Alloc = std::allocator<Ch> >
    class basic_format;

typedef basic_format<char >     format;

template<class Ch, class Tr, class Alloc>
class basic_format
{
public:
    explicit basic_format(const Ch* str = NULL);
    explicit basic_format(const string_type& s);
    basic_format(const basic_format& x);
    basic_format& operator= (const basic_format& x);

    basic_format& clear();       // 清空緩存
    basic_format& parse(const string_type&); // 重新格式化

    size_type   size() const;    // 獲取字符串長度
    string_type str()  const;    // 獲取格式化後的字符串

    template<class T>
    basic_format&   operator%(const T& x); //重載操作符%

    template<class Ch2, class Tr2, class Alloc2>
    friend std::basic_ostream<Ch2, Tr2> &
        operator<<(std::basic_ostream<Ch2, Tr2> &,
        const basic_format<Ch2, Tr2, Alloc2>&); //流輸出
}; // class basic_format
  • str: 返回format對象內部已經格式化號的字符串
  • size : 返回format對象格式化號的字符串長度,可以直接從str()返回的string.size()
  • parse :重新格式化,清空format對象內部緩存,改用一個新的格式化字符串,如果只是想清空緩存,則使用clear(),它把format對象恢復到初始化狀態
  • operator% : 可以接受待格式化的任意參數,%輸入的參數個數必須等於格式化字符串中要求的個數,過多或者過少都會拋出異常
  • operator<<:重載流輸入操作符,可以直接輸出格式化好的字符串

不過要注意的是,透過operator%傳給boost::format對象的變量是會儲存在對象內部的,所以可以分批的傳入變數;但是如果變量的數量不符合的話,在編譯階段雖然不會出現錯誤,可是到了執行階段還是會讓程序崩潰,所以在使用上必須小心一點。 不過,在有輸出後,是可以再重新傳入新的變量、重複使用同一個boost::format 對象的。

格式化語法

format基本繼承了printf的格式化語法,格式化選項以%開始,後面是格式規則

%[標誌][輸出最少寬度][.精度][長度]類型

詳細請參考printf格式輸出

除了支持printf格式化外,還新增了格式:

  • %|spec| :與printf格式選項功能相同,但是兩邊增加豎線分隔,更好的區分格式化選項與普通字符
  • %N% :標記第N個參數,相當於佔位符,不帶任何其他格式化的選項

通過以下使用豎線分隔,更加清楚明瞭格式化參數

format fmt("%05d\n%-8.3f\n% 10s\n%05X\n");
format fmt("%|05d|\n%|-8.3f|\n%| 10s|\n%|05X|\n");

使用樣例

#include <boost/format.hpp>
#include <iostream>
using namespace std;
using namespace boost;

int main()
{
    cout << "-------------"<<endl;
    format fmt("%d + %d = %d");
    fmt % 2 % 3 % 5;
    cout << fmt.str() << endl;

    cout << "-------------"<<endl;
    format fmt2("%05d\n%-8.3f\n% 10s\n%05X\n");
    fmt2 % 123;
    fmt2 % 456.7;
    fmt2 %"boost" % 100;
    cout << fmt2 << endl;

    cout << "-------------"<<endl;
    cout << boost::format("x=%1%,  y=%2% ,z= %3%") % "format" % 40.2 % 134 << endl;
    cout << "-------------"<<endl;
    return 0;
}

Output:

-------------
2 + 3 = 5
-------------
00123
456.700
     boost
00064

-------------
x=format,  y=40.2 ,z= 134
-------------
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章