Boost中包括五個字串與文本處理領域的程式庫:
【1】兩個與c標準庫函數功能類似的lexical_cast和format,它們關注與字串的表示,可以將數值轉化為字串,對輸出做精確的格式化。
【2】string_algo庫提供了大量常用的字串處理函數
【3】tokenizer和xpressive,前者是一個分詞器,後者則是一個靈活的Regex分析器,同時也是一個文法分析器.
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;
}