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()等,这里就很少介绍了。