boost string_algo

来源:互联网 发布:淘宝账户注销后会怎样 编辑:程序博客网 时间:2024/05/16 05:06

string_algo:
 std::string符合容器的定义,可以把它看做元素类型为char(或wchar_t)的序列容器,可以使用标准算法来对它进行运算。
 string_algo库是一个非常全面的字符串算法库,提供了大量的字符串操作函数,如大小写无关比较,修剪,特定模式的子串查找等,可以再不使用正则表达式的情况下处理大多数字符串相关问题。
#include<boost/algorithm/string.hpp>
using namespace boost;
示例:
#include <assert.h>
#include <iostream>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <iomanip>
using namespace boost;
using namespace std;
int main()
{
 string str("readme.txt");
 if (ends_with(str, "txt"))      //判断后缀
 {
  cout<< to_upper_copy(str) + " UPPER"<<endl; //大写
  assert(ends_with(str, "txt"));
 }
 replace_first(str, "readme", "followme");  //替换
 cout<<str<<endl;
 vector<char> v(str.begin(), str.end());   //一个字符的vector
 vector<char> v2 = to_upper_copy(erase_first_copy(v, "txt")); //删除字符串
 for (int i = 0; i < v2.size(); ++i)
  cout<<v2[i];
 system("pause");
 return 0;
}

string_algo概述:
 string_algo被设计用于处理字符串,然后它的处理对象并不一定是string或basic_string<T>,可以是任何符合boost.range要求的容器。容器内的元素也不一定是char或wchar_t,任何可拷贝构造和赋值的类型均可。
 不过使用string_algo库主要的工作对象还是字符串string和wstring,它也可以工作在标准容器vector,deque,list和非标准容器slist,rope上,为求简便,接下来的讨论都基于std::string.

 string_algo库基于boost.range,因此避免了标准库算法必须提供begin()和end()迭代器的麻烦,也使得算法可以嵌套在一起串联处理字符串。
 string_algo库中的算法命名规则遵循了标准库的惯例,算法名均为小写形式,并使用不同的前缀或后缀来区分不同的版本,命名规则如下;
 【1】前缀i,表明算法是大小写不敏感的,否则是大小写敏感的
 【2】后缀_copy:表明算法不变动输入,返回处理结果的拷贝,否则算法原地处理,输入即输 出。 
 【3】后缀_if:表明算法需要一个作为判断式的谓词函数对象,否则使用默认的判断准则。

string_algo库提供的算法共分五大类,如下:
 【1】大小写转换;
 【2】判断式与分类; 
 【3】修剪;
 【4】查找与替换;
 【5】分隔与合并。

大小写转换:
 两组算法:to_upper()和to_lower().
声明如下:
template<typename T> void to_upper(T & Input);
template<typename T> void to_lower(T & Input);
这两个算法具有后缀为_copy的版本,基本算法直接把输入在原地改变大小写,而copy版本则不变动输入,返回变动后的一个拷贝:
示例:
#include <boost/algorithm/string.hpp>
#include <iomanip>
using namespace boost;
using namespace std;
int main()
{
 string str("I Don't Know.\n");
 cout<<to_upper_copy(str); // 返回大写拷贝
 cout<<str;     //原字符串不改变
 to_lower(str);    //字符串小写
 cout<<str;     //原字符串改变
 system("pause");
 return 0;
}

判断式(算法):
判断式算法可以检测两个字符串之间的关系,包括:
 【1】starts_with:检测一个字符串是否是另一个的前缀;
 【2】ends_with: 。。。。。。。。。。。。。。。后缀;
 【3】contains:检测一个字符串是否被另一个包括;
 【4】equals:检测两个字符串是否相等;
 【5】lexicographical_compare;根据字典顺序检测一个字符串是否小于另一个;
 【6】all,检测一个字符串中的所有元素是否满足指定的判断式。
 除了all,这些算法都有另一个i前缀的版本,由于他们不变动字符串,因此没有_copy版本.

这些算法的声明如下:
template<typename Range1T, typename Range2T>
bool starts_with(const Range1T & Input, const Range2T & Test);
template<typename Range1T, typename Range2T>
bool ends_with(const Range1T & Input, const Range2T & Test);
template<typename Range1T, typename Range2T>
bool contains(const Range1T & Input, const Range2T & Test);
template<typename Range1T, typename Range2T>
bool equals(const Range1T & Input, const Range2T & Test);
template<typename Range1T, typename Range2T>
bool lexicographical_compare(const Range1T & Arg1, const Range2T & Arg2);
template<typename RangeT, typename PredicateT>
bool all(const RangeT & Input, PredicateT Pred);
 注意:它们的名称略微违背了string_algo库的命名原则,它们同时还要一种接受比较谓词函数对象的三参数版本,而没有使用_if后缀,谓词用于逐个地对字符串元素进行比较,相当于Pred(a[i], b[i]).
示例:
#include <boost/algorithm/string.hpp>
#include <iomanip>
using namespace boost;
using namespace std;
int main()
{
 string str("Power Bomb");
 assert(iends_with(str, "bomb"));
 assert(!ends_with(str, "bomb"));
 assert(starts_with(str, "Pow"));
 assert(contains(str, "er"));
 string str2 = to_lower_copy(str);
 assert(iequals(str, str2));
 string str3("power suit");
 assert(ilexicographical_compare(str, str3)); //大小写无关比较
 assert(all(str2.substr(0,5), is_lower()));
 system("pause");
 return 0;
}

判断式(函数对象):
 string_algo增强了标准库中的equal_to<>和less<>函数对象,允许对不同类型的参数进行比较,并提供大小写无关的形式。
 【1】is_equal:类似equals算法,比较两个对象是否相等。
 【2】is_less:比较两个对象是否具有小于关系。
 【3】is_not_greater:比较两个对象是否具有不大于关系.
示例:
#include <boost/algorithm/string.hpp>
#include <iomanip>
using namespace boost;
using namespace std;
int main()
{
 string str1("Samus"), str2("samus");
 assert(!is_equal()(str1, str2));
 assert(is_less()(str1, str2));
 system("pause");
 return 0;
}
 注意:函数对象名称后两个括号,第一个括号调用了函数对象的构造函数,产生了一个临时对象,第二个括号才是真正的函数调用操作符operator().

分类:
 string_algo提供了一组分类函数,可以用于检测一个字符串是否符合某种特性,主要用于搭配其他算法:
 【1】is_space:字符是否为空格;
 【2】is_alnum:字符是否为字母和数字字符;
 【3】is_alpha:字符是否为字母;
 【4】is_cntrl:字符是否为控制字符;
 【5】is_digit:字符是否问十进制数字;
 【6】is_graph:字符是否为图形字符;
 【7】is_lower:字符手法为小写字符;
 【8】is_print:字符是否为打印字符;
 【9】is_punct:字符是否为标点符号字符;
 【10】is_upper:字符是否为大写字符;
 【11】is_xdigit:字符是否为十六进制数字;
 【12】is_any_of:字符是否是参数字符序列中的任意字符;
 【13】if_from_range:字符是否位于指定区间内,即form<=ch<=to;
 注意:这些函数并不真正地检测字符,而是返回一个类型为detail::is_classifiedF的函数对象,这个函数对象的operator()才是真正的分类函数(因此,这些函数都属于工厂函数)。
函数对象is_classifiedF重载了逻辑运算符||,&&和!,可以使用逻辑运算符把它们组合成逻辑表达式,以实现更复杂的条件判断;

 如果string_algo提供的这些分类判读式不能满足要求,我们也可以自己实现专用的判断式,定义一个返回值为bool的函数对象就可以了,示例判断字符是否为0或1的代码,它等价于is_any_of("01"):
struct is_zero_or_one
{
 bool operator()(char &x)
 {return x == '0' || x == '1';}
};

修剪:
 string_algo提供3个修剪算法,trim_left,trim_right和trim
 修剪算法可以删除字符串开发或结尾部分的空格,它有_if和_copy两种后缀,因此么个算法有四个版本,_if版本接受一个判断式IsSpace,将所有被判定为空格(IsSpace(c) == true)的字符删除.
示例:
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include <iomanip>
using namespace boost;
using namespace std;
int main()
{
 format fmt("|%s|\n");
 string str = " samus aran ";
 cout<<fmt % trim_copy(str);
 cout << fmt % trim_left_copy(str);
 trim_right(str);
 cout<< fmt % str;
 string str2 = "2012 Happy new Year!!!";
 cout<<fmt %  trim_left_copy_if(str2, is_digit());//删除左端的数字
 cout<<fmt %  trim_right_copy_if(str2, is_punct());//删除左端的数字
 cout<<fmt % trim_copy_if(str2, is_punct() || is_digit() || is_space());
 system("pause");
 return 0;
}

查找:
 string_algo的查找算法提供与std::seach()类似的功能,但接口不太一样,它不是返回一个迭代器(查找到的位置),而使用了boost.range库的iterator_range返回查找到的整个区间,获得了更多的信息,便于算法串联和其他处理(比如,根据iterator_range的两个迭代器将原字符串拆成三份).
 iterator_range,它的概念上类似std::pair<iterator, iterator>, 包装了两个迭代器,可以用begin()和end()访问,相当于定义了一个容器的子区间,并可以像原容器一样使用。
 string_algo提供的查找算法包括:
 【1】查找字符串在输入中第一次出现的位置。
 【2】查找字符串在输入中最后一次出现的位置。
 【3】查找字符串在输入中的第n次(从0开始计数)出现的位置。
 【4】取一个字符串开头N个字符的字串,相当于substr(0,n);
 【5】取一个字符串末尾N个字符的字串。
声明如下:
template<typename Range1T, typename Range2T>
 iterator_range find_first(Range1T & Input, const Range2T & Search);
template<typename Range1T, typename Range2T>
 iterator_range find_last(Range1T & Input, const Range2T & Search); 
template<typename Range1T, typename Range2T>
 iterator_range find_nth(Range1T &Input, const Range2T & Search, int Nth);
template<typename RangeT>
 find_head(RangeT &Input, int N);
template<typename RangeT>
 find_tail(RangeT & Input, int N);
 这些算法有i前缀的版本;
示范:
#include <assert.h>
#include <iostream>
#include <vector>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
using namespace boost;
using namespace std;
int main()
{
 format fmt("|%s|.pos = %d\n");
 string str = "Long long ago, there was a king.";
 iterator_range<string::iterator> rge; //迭代器区间
 rge = find_first(str, "long"); //找第一次出现
 cout<< fmt % rge % (rge.begin() - str.begin());
 rge = ifind_first(str, "long");
 cout<< fmt % rge % (rge.begin() - str.begin());
 rge = find_nth(str, "ng", 2);  //找第三次出现的位置
 cout<< fmt % rge % (rge.begin() - str.begin());
 rge = find_head(str, 4);   //取前4个字符
 cout<< fmt % rge % (rge.begin() - str.begin());
 rge = find_tail(str, 5);   //取末尾5个字符
 cout<< fmt % rge % (rge.begin() - str.begin());
 rge = find_first(str, "samus");  //找不到
 assert(rge.empty() && !rge);
 system("pause");
 return 0;
}
 最后两个说明iterator_range可以像标准容器一样判读是否为空,也可以隐式转换为bool值
 string_algo库还有另外三个查找算法,find_token,find_regex和通用的find算法

替换与删除:
 替换,删除操作时在查找到结果后再对字符串进行处理,它们算法名称很相似:
 【1】replace/erase_first:替换/删除一个字符串在输入中的第一次出现;
 【2】replace/erase_last:。。。。。。。。。。。。。。。最后一次出现;
 【3】replace/erase_nth:。。。。。。。。。。。。。。。。第n次(从0开始)出现;
 【4】replace/erase_all:。。。。。。。。。。。。。。。。所有出现;
 【5】replace/erase_head:替换/删除输入开头;
 【6】replace/erase_tail:替换/删除输入结尾;
 前八个算法每个都有前缀i,后缀_copy和组合,有四个版本,后四个只有后缀_copy的两个版本。

replace算法声明:
 template<typename SequenceT, typename Range1T, typename Range2T>
 void replace_first(SequenceT & Input, const Range1T & Search, const Range2T & Format);
 template<typename SequenceT, typename Range1T, typename Range2T>
 void replace_last(SequenceT &Input, const Range1T & Search, const Range2T & Format); 
 template<typename SequenceT, typename Range1T, typename Range2T>
 void replace_all(SequenceT & Input, const Range1T & Search, const Range2T & Format);
 template<typename SequenceT, typename Range1T, typename Range2T>
 void replace_nth(SequenceT &Input, const Range1T & Search, const Range2T & Format);
 template<typename SequenceT, typename Range1T, typename Range2T>
 void replace_nth(SequenceT & Input, const Range1T & Search, int Nth, const Range2T & Format);
 template<typename SequenceT, typename RangeT>
 void replace_head(SequenceT &Input, int N, const RangeT & Format);
 template<typename SequenceT, typename RangeT>
 void replace_tail(SequenceT &Input, int N, const RangeT & Format);
erase算法的声明如下: 
 template<typename SequenceT, typename RangeT>
 void erase_first(SequenceT &Input, const RangeT & Search);
 template<typename SequenceT, typename RangeT>
 void erase_last(SequenceT &Input, const RangeT & Search);
 template<typename SequenceT, typename RangeT>
 void erase_nth(SequenceT &Input, const RangeT & Search, int Nth);
 template<typename SequenceT, typename RangeT>
 void erase_all(SequenceT &Input, const RangeT & Search);
 template<typename SequenceT> void erase_head(SequenceT & Input, int N);
 template<typename SequenceT> void erase_tail(SequenceT & Input, int N);
示范:
#include <boost/algorithm/string.hpp>
using namespace boost;
using namespace std;
int main()
{
 string str = "Samus beat the monster.\n";
 cout<<replace_first_copy(str, "Samus", "samus");
 replace_last(str, "beat", "kill");
 cout<<str;
 replace_tail(str, 9, "ridley.\n");
 cout<<str;
 cout<<ierase_all_copy(str, "samus");
 cout<<replace_nth_copy(str, "l", 1, "L");
 cout<<erase_tail_copy(str, 8);
 system("pause");
 return 0;
}

分割:
 string_algo提供了两个字符串分割算法,find_all(虽然名称有find,但功能被归类为分割算法)和split,可以使用某种策略把字符串分割成若干部分,并将分割厚后的字符串拷贝存入指定的容器.
 分割算法对容器类型的要求是必须能够持有查找到结果的拷贝或者引用,因此容器的元素类型必须是string或者iterator_range<string::iterator>,容器则可以是vector,list,deque等标准容器.
 声明如下:
 template<typename SequenceSequenceT, typename Range1T, typename Range2T>
 SequenceSequenceT & find_all(SequenceSequenceT & Result, Range1T & Input, const Range2T & Search);
 find_all算法类似普通的查找算法,它搜索所有匹配的字符串,加入到容器中,有一个i版本

 template<typename SequenceSequenceT, typename RangeT, typename PredicateT>
 SequenceSequenceT & find_all(SequenceSequenceT & Result, RangeT & Input, PredicateT Pred, token_compress_mode_type eCompress = token_compress_off);
 split算法使用判断式Pred来确定分割的依据,如果字符ch满足判断式Pred(Pred(ch) == true),那么它就是一个分割符,将字符串从这里分割。
  参数eCompress可以取值为token_compress_on或token_compress_off,如果值为前者,那么当两个分割符连续出现时将被视为一个,如果为token_compress_off则两个连续的分隔符标记了一个空字符串,参数eCompress默认取值为token_compress_off。
示例:
#include <assert.h>
#include <iostream>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/typeof/typeof.hpp>
using namespace boost;
using namespace std;
int main()
{
 string str = "Samus,link.Zelda::Maric-Luigi+zelda";
 deque<string> d;
 ifind_all(d, str, "zELDA");  //大小写无关分割字符串
 assert(d.size() == 2);
 for (BOOST_AUTO(pos, d.begin()); pos != d.end(); ++pos)
 {
  cout<<"["<<*pos<<"] ";
 }
 cout<<endl;
 list<iterator_range<string::iterator>> l;
 split(l, str, is_any_of(",.:-+")); //使用标点分割
 for(BOOST_AUTO(pos, l.begin()); pos != l.end(); ++pos)
 {
  cout<<"["<<*pos<<"]";
  
 }
 cout<<endl;
 l.clear();
 split(l, str, is_any_of(".:-"), token_compress_on);   //那么当两个分割符连续出现时将被视为一个
 for (BOOST_AUTO(pos, l.begin()); pos != l.end(); ++pos)
 {
  cout <<"["<<*pos<<"]";
 }
 cout<<endl;
 system("pause");
 return 0;
}

合并:
 合并算法jion是分割算法的逆运算,它把存储在容器中的字符串连接成一个新的字符串,并且可以指定连接的分隔符.
 合并算法声明如下:
 template<typename SequenceSequenceT, typename Range1T>
 range_value<SequenceSequenceT>::type
 jion(const SequenceSequenceT & Input, const Range1T & Separator);
 join还有一个后缀_if的版本,它接受一个判断式,只有满足判断式的字符串才能参与合并。
示范:
#include <assert.h>
#include <iostream>
#include <vector>
#include <boost/assign.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/typeof/typeof.hpp>
using namespace boost;
using namespace std;
int main()
{
 using namespace boost::assign;
 vector<string> v = list_of("Samus")("Link")("Zelda")("Mario");
 cout<<join(v, "+")<<endl;  //合并
 //定义一个简单的函数对象
 struct is_contains_a
 {
  bool operator()(const string &x)
  {
   return contains(x, "a");
  }
 };
 cout<< join_if(v, "**", is_contains_a()); //合并
 system("pause");
 return 0;
}
 程序首先使用assign库向vector添加了四个字符串,然后以"+"合并,随后定义了一个简单的函数对象,它包装了算法contains,判断字符串是否包含字符a,最后把这个函数对象作为参数传递给join_if算法。

查找(分割)迭代器:
 在通用的find_all或split外,string_algo库还提供两个查找迭代器find_iterator和split_iterator,它们可以在字符串中像迭代器那样遍历匹配,进行查找或分割,无需使用容器来容纳。
示范:
#include <assert.h>
#include <iostream>
#include <vector>
#include <boost/assign.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/typeof/typeof.hpp>
using namespace boost;
using namespace std;
int main()
{
 string str("Samus||samus||mario||||Link");
 //查找迭代器类型定义
 typedef find_iterator<string::iterator> string_find_iterator;
 string_find_iterator pos, end;  //声明查找迭代器变量
 for (pos = make_find_iterator(str, first_finder("samus", is_iequal())); pos != end; ++pos)
  cout<<"["<<*pos<<"]";
 cout<<endl;
 //分割迭代器类型定义
 typedef split_iterator<string::iterator> string_split_iterator;
 string_split_iterator p, endp;
 for (p = make_split_iterator(str, first_finder("||", is_iequal())); p != endp; ++p)
  cout<<"["<<*p<<"]";
 cout<<endl;
 system("pause");
 return 0;
}

 使用查找迭代器首先要声明迭代器对象find_iterator或split_iterator,它们的模板类型参数是一个迭代器类型a,例如string::iterator或者char*.
 调用first_finder()函数获得迭代器的起始位置,它用于判断匹配的对象,然在用make_find_iterator或make_split_iterator来真正迭代器,同族查找函数还有last_finder,nth_finder,token_finder等,它们的含义与查找算法类似,从不同的位置开始查找返回迭代器。

 初始化工作完成后,就可以像使用标准迭代器或者指针那样,不断地遍历迭代器对象,使用解引用操作符获取查找的内容,直到找不到匹配的对象,
 注意,分割迭代器的运用,它可以是任意长度的字符串作为分割符进行分割,而普通的split算法则只能以字符作为分隔符。

原创粉丝点击