c++在stl庫中提供了一個string類用以代替c語言的char*來實現字符串功能,不過stl的string只提供了一個鏈接字符串和查找的功能,其它的經常使用函數幾乎一概沒有,就連字符串替換都得本身來實現,和c#的字符串函數比起來簡直弱爆了。html
boost庫在頭文件<boost/algorithm/string.hpp>中提供了很多字符串處理函數,用以幫助咱們實現基本的字符串處理功能,極大程度上緩解了字符串函數不夠用的問題。c++
string str1("hello abc-*-ABC-*-aBc goodbye");
vector<string> SplitVec; // #2: Search for tokens
split(SplitVec, str1, is_any_of("-*"), token_compress_on); // SplitVec == { "hello abc","ABC","aBc goodbye" }git
上述代碼就提供了一個split的功能,不過和c#的版本相比,仍是不夠簡潔,若是設計成這樣就更加好用了:算法
auto SplitVec = split(str1, is_any_of("-*"), token_compress_on);c#
之因此不以這種形式設計,貌似是由於若是在split函數裏構造返回值的話,會有一次數據拷貝的開銷。從中也能夠看出,boost的設計仍是以性能爲主的。而.net程序自然沒有返回值拷貝帶來的開銷,能夠採起那種更簡潔的接口形式。函數
PS:我以爲能夠像.net那樣,在堆變量中保存結果,而後經過auto_ptr封裝後做做爲返回值。即有簡潔的接口形式,又沒有數據拷貝的開銷,堆變量也能經過auto_ptr自動釋放。性能
一樣,也是出於性能方向的考慮,對於會產生新字符串的函數,每每會有一個xxx和xxx_copy兩個版本,例如tolower就有to_lower和to_lower_copy兩個版本:一個是直接變動自己的值,一個是構造新字符串,具體選取那個根據實際場景來考慮。ui
另外,字符串比較函數中,每每有區分大小寫和不區分大小寫的算法。在boost中並非經過參數來控制,而是直接提供xxx和ixxx兩個版本,其中i就表示ignor case。如equals和iequals。還有的須要和條件函數一併使用的,這時就會提供一個xxx_if的版本。spa
因爲提供的字符串函數比較多,這裏我只按每類列舉幾個經常使用的函數和示例,若是同一個算法有xxx_copy的版本或ixxx版本,也只列舉基本的形式。其它的情參看boost文檔。.net
大小寫轉換涉及到四個函數:to_upper()、to_upper()以及xxx_copy的版本。基本用法以下:
cout << to_upper_copy(string("hello world")) << endl;
Trimming函數主要有trim()、trim_left()、trim_right()和他們的xxx_copy和xxx_if版本。用於去除字符串首位的空白字符:
cout << trim_copy(std::string(" hello world")) << endl;
固然,也不限於只去掉空白字符:
cout << trim_copy_if(std::string(",,,hello world"), is_any_of(" ,.:")) << endl;
Predicates函數主要有:starts_with() 、ends_with() 、contains() 、equals() 、lexicographical_compare() 、all()以及他們的ixxx版本。基本上從名字裏就能夠看出怎麼用了:
cout << (ends_with("hello world", "world") ? "true" : "false") << endl;
查找算法有好幾種:find()、first()、find_last()、find_nth() 、find_head()、find_tail()、find_token()、find_regex()。常見的用法以下:
auto result = find_first("hello world", "world");
if(result.empty())
cout << "can't find result" << endl;
else
cout << result << endl;
其中result是一個boost::iterator_range類型的對象,能夠用它來構造子串。
string s("hello world");
cout << s.substr(find_first(s, "wo").begin() - s.begin()) <<endl;
或者來個更復雜點的:
string str1("abc-*-ABC-*-aBc");
for(auto it = make_find_iterator(str1, first_finder("abc", is_iequal())); !it.eof(); ++it)
{
cout << copy_range<std::string>(*it) << endl;
}
boost把erase和replace函數分開來列了,這樣的好處是命名比較清晰,但很差的地方時函數變得很是多,不如重載的形式那麼好記。
replace的函數有replace_all() 、replace_first()、 replace_last() 以及它們的變體,加上erase,共有20多種,這裏就不一一列舉了。
cout << replace_all_copy(string("hello world"), "l", "-") << endl;
split函數的用法前面以及介紹過:
string str1("hello abc-*-ABC-*-aBc goodbye");
vector<string> SplitVec;
split(SplitVec, str1, is_any_of("-*"), token_compress_on);
須要注意的是這裏的token_compress_on參數,它能夠吧連續多個分隔符當一個,默認沒有打開,當用的時候通常是要打開的。
另外,boost把find_all函數也分到split一類裏面去了,它們的用法到也確實相似。
string str1("hello abc-*-ABC-*-aBc goodbye");
typedef vector<iterator_range<string::iterator>> find_vector_type;
find_vector_type FindVec;
ifind_all( FindVec, str1, "abc" );
Join函數則是和split相反,用於把多個字符串拼接起來。
std::array<string, 3> k = {"hello", "world", "123"};
cout << join(k, "-"); //輸出結果爲: hello-world-123
它要求先把參數放到容器裏,不像.net的那樣能夠直接傳入動態參數那樣好用,若是能寫成這樣的重載形式會更好點(固然,本身封一個也不難):
join("-", "hello", "world", "123", …)
其它還有一些條件函數,主要配合算法使用。如前面已經見過的is_any_of()、經常使用的還有is_upper()、is_lower()、is_digit()、is_space()等,這裏就很少介紹了。