BOOST库 之 string_algo 字符串的增删改查

一、包含
#include <boost/algorithm/string.hpp>

二、摘要

被设计用于处理字符串,但其元素不一定是char或wchar_t,任何可拷贝构造和辅助的类型均可.

std::string str( "readme.txt" ); 
if ( boost::ends_with(str, "txt") )//判断后缀是否为txt
{
	std::cout << boost::to_upper_copy(str) + " UPPER" << std::endl; //输出字符串的大写,不改变原字符串
}

boost::replace_first( str, "readme", "followme" );//将第一个出现readme的字符替换成followme
cout << str << endl;

vector<char> v( str.begin(), str.end() );

//erase_first_copy:返回删除第一个"txt"的字符串
vector<char> v2 = boost::to_upper_copy( boost::erase_first_copy(v, "txt") );
for ( int i = 0; i < v2.size(); ++i )
{
	cout << v2[i];
}

三、算法
算法名均为小写形式,并使用不同的前缀或后缀来区分不同的版本,命名规则如下:
①前缀i     : 有这个前缀表明算法是大小写不敏感的,否则是大小写敏感的;
②后缀_copy : 有这个后缀表明算法不变动输入,返回处理结果的拷贝,否则算法原地处理,输入即输出;
③后缀_if   : 有这个后缀表明算法需要一个作为判断式的谓词函数对象,否则使用默认的判断准则.

五大类算法
①、大小写转换
②、判断式与分类
③、修剪
④、查找与替换
⑤、分割与合并

//①、大小写转换

//直接把输入在原地改变大小写
boost::to_upper(T & Input);
boost::to_lower(T & Input);

//不变动输入,返回变动后的一个拷贝
T & Input boost::to_upper_copy(T & Input);
T & Input boost::to_lower_copy(T & Input);
//②'、判断式(算法)
//判断式算法可以检测两个字符串之间的关系,包括:
//starts_with   : 检测一个字符串是否是另一个的前缀;
//ends_with     : 检测一个字符串是否是另一个的后缀;
//contains      : 检测一个字符串是否被另一个包含;
//equals        : 检测两个字符串是否相等;
//lexicographical_compare : 根据字典顺序检测一个字符串是否小于另一个;
//all           : 检测一个字符串中的所有元素是否满足指定的判断式.

//【注】除了all,这些算法都有另一个i前缀的版本。

//例
{
	std::string str( "Power Bomb" );

	assert( boost::iends_with(str, "bomb") );//大小写无关检测后缀;
	assert( !boost::ends_with(str, "bomb") );//大小写敏感检测后缀;

	assert( boost::starts_with(str, "Pow") );//检测前缀;

	assert( boost::contains(str, "er") ); //测试包含关系;

	std::string str2 = boost::to_lower_copy( str );
	assert( iequals(str, str2) ); //大小写无关判断想定;

	std::string str3( "power suit" );
	assert( ilexicographical_compare(str, str3) );//大小写无关比较;

	assert( boost::all(str2.substr(0, 5), boost::is_lower()) ); //检测字符串均小写;
}

//②"、判断式(函数对象)
//摘要
//允许对不同类型的参数进行比较,并提供大小写无关的形式

//is_equal       : 类似equals算法,比较两个对象是否相等;
//is_less        : 比较两个对象是否具有小于关系;
//is_not_greater : 比较两个对象是否具有不大于关系;

//例
{
	std::string str1( "Samus" ), str2( "samus" );

	assert( !boost::is_equal()( str1, str2 ) );
	assert( boost::is_less()( str1, str2 ) );//A:65; a:97;

	//ASCII码
	//0~9 : 58~57
	//a~z : 97~122
	//A~Z : 65~90
}
//注意 函数对象名称后的两个括号,第一个括号调用了函数对象的构造函数,产生一个临时对象,
//第二个括号才是真正的函数调用操作符operator()

②'"、分类
用于检测一个字符是否符合某种特性,主要用于搭配其他算法,比如上边的all


is_space     : 字符是否为空格;
is_alnum     : 字符是否为字母和数字字符;
is_alpha     : 字符是否为字母;
is_cntrl     : 字符是否为控制字符;
is_digit     : 字符是否为十进制数字;
is_graph     : 字符是否为图形字符;
is_lower     : 字符是否为小写字符;
is_print     : 字符是否为可打印字符;
is_punct     : 字符是否为标点符号字符;
is_upper     : 字符是否为大写字符;
is_xdigit    : 字符是否为十六进制数字;
is_any_of    : 字符是否是参数字符序列中的任意字符;
if_from_range : 字符是否位于指定区间内,即from <= ch <= to.


【注】这些函数并不是真正的检测字符,而是返回一个类型为detail::is_classifiedF的函数对象,
这个函数对象的operator()才是真正的分类函数.

//③、修剪
//摘要
//	修剪算法可以删除字符串开头或结尾部分的空格,它有_if和_copy两种后缀
//trim_left、trim_right、trim

{
	boost::format fmt( "|%s|\n" );

	std::string str = "  samus aram  ";
	cout << fmt % boost::trim_copy(str); //删除两端的空格
	cout << fmt % boost::trim_left_copy(str); //删除左端空格

	boost::trim_right( str ); //原地删除右端的空格
	cout << fmt % str;

	std::string str2 = "2010 Happy new Year!!!";
	cout << fmt % boost::trim_left_copy_if( str2, boost::is_digit() ); //删除左端的数字;
	cout << fmt % boost::trim_right_copy_if( str2 , boost::is_punct() ); //删除右端的标点;
	cout << fmt % boost::trim_copy_if( str2, is_punct() || is_digit() || is_space() ); //删除两端的标点、数字和空格

	//运行结果;
	//|samus aran|
	//|samus aran  |
	//|  samus aran|
	//| Happy new Year!!!|
	//|2010 Happy new Year|
	//|Happy new Year|
}

//④'、查找
//摘要
//	string_algo的查找算法提供与std:search()类似的功能,但接口不大一样。它不是返回一个迭代器(查找到的位置),而使用了boost.range库的iterator_range返回
//查找到的整个区间,获得了更多的信息,便于算法串联和其他处理(比如:根据iterator_range的两个迭代器将原字符串拆成三分)。
//	在这里简单介绍一下iterator_range。它概念上类型std::pair<iterator,iterator>,包装的两个迭代器,可以用begin()和end()访问,
//相当于定义了一个容器的子区间,并可以像原容器一样使用.
		
//find_first   : 查找字符串在输入中第一次出现的位置;
//find_last    : 查找字符串在输入中最后一次出现的位置;
//find_nth     : 查找字符串在输入中的第n次(从0开始计数)出现的位置;

//find_head    : 取一个字符串开头N个字符的字串,相当于substr(0,n);
//find_tail    : 取一个字符串末尾N个字符的字串.

//这些算法都不变动字符串,因此没有_copy后缀版本,但其中前三个算法有i前缀的版本.
{
	boost::format fmt( "|%s|.pos = %d\n" );
	std::string str = "Long long ago, there was a king.";

	boost::iterator_range<std::string::iterator> rge; //迭代器区间;

	rge = boost::find_first( str, "long" );  //找第一次出现;
	cout << fmt % rge % ( rge.begin() - str.begin() );

	rge = boost::ifind_first( str, "long" );  //大小写无关 找第一次出现;
	cout << fmt % rge % ( rge.begin() - str.begin() );

	rge = boost::find_nth( str, "ng", 2 );  //找第三次出现;
	cout << fmt % rge % ( rge.begin() - str.begin() );

	rge = boost::find_head( str, 4 );  //取前4个字符;
	cout << fmt % rge % ( rge.begin() - str.begin() );

	rge = boost::find_tail( str, 5 );  //取末尾5个字符;
	cout << fmt % rge % ( rge.begin() - str.begin() );

	rge = boost::find_first( str, "samus"); //找不到;
	assert( rge.empty() && !rge );

	//运行结果;
	//|long|.pos = 5
	//|Long|.pos = 0
	//|ng|.pos = 29
	//|Long|.pos = 0
	//|king.|.pos = 27
}

//④"、替换与删除
//摘要
//	替换、删除操作与查找算法非常接近,是在查找到结果后再对字符串进行处理

// replace/erase_first   : 替换/删除一个字符串在输入中的第一次出现;
// replace/erase_last    : 替换/删除一个字符串在输入中的最后一次出现;
// replace/erase_nth     : 替换/删除一个字符串在输入中的第n次(从0开始)出现;
// replace/erase_all     : 替换/删除一个字符串在输入中的所有出现;

// replace/erase_head    : 替换/删除输入的开头;
// replace/erase_tail    : 替换/删除输入的末尾;

//	前八个(前四行)算法每个都有前缀i、后缀_copy和组合,后四个(后两行)则只有后缀_copy的两个版本.

{
	std::string str = "Samus beat the monster.\n";

	cout << boost::ireplace_first_copy( str, "Samus", "samus" );

	boost::replace_last( str, "beat", "kill" );
	cout << str;

	boost::replace_tail( str, 9, "ridley.\n" );
	cout << str;

	cout << boost::ierase_all_copy( str, "samus" );
	cout << boost::replace_nth_copy( str, "l", 1, "L" );
	cout << erase_tail_copy( str, 8 );

	//运行结果;
	//|samus beat the monster.|
	//|Samus beat the monster.|
	//|Samus beat the monster.|
	//| kill the ridley.|
	//|Samus kilL the ridley.|
	//|Samus kill the |
}

//⑤'、分割
//	分割算法对容器类型的要求是必须能够持有查找到结果的拷贝或者引用,因此容器的元素类型必须是string或者boost::iterator_range<std::string::iterator>,
//容器则可以使vector、list、deque等标准容器。

// find_all : 类似与普通的查找算法,它搜索所有的匹配的字符串,加入到容器中,有一个忽略大小写的前缀i版本.
// split    : 使用判断式Pred来确定分割的依据,如果字符ch满足判断式Pred( Pred(ch)==true ),那么它就是一个分隔符,将字符串从这里分割.

// find_all 函数声明如下
template<typename SequenceSequenceT, typename RangeT, typename Range2T>
SequenceSequenceT & find_all( SequenceSequenceT & Result, RangeT & Input, const Range2T & Search );

// split 函数声明如下
template<typename SequenceSequenceT, typename RangeT, typename PredicateT>
SequenceSequenceT & split( SequenceSequenceT & Result, RangeT & Input, PredicateT Pred, token_compress_mode_type eCompress = token_compress_off );
//[注]参数 eCompress 可以取值为token_compress_off或token_compress_on,如果值为_on 那么当两个分隔符连续出现时将被视为一个,如果为_off则两个连续的分隔符
//标记了一个空字符串.参数 eCompress 默认取值为 _off

{
	std::string str = "Samus,Link.Zelda::Mario-Luigi+zelda";

	std::deque<std::string> d;
	boost::ifind_all( d, str, "zELDA" ); //大小写无关分割字符串;
	assert( d.size() == 2);

	//使用BOOST_AUTO需#include <boost\typeof\typeof.hpp>
	for ( BOOST_AUTO(pos, d.begin()); pos != d.end(); ++pos )
	{
		cout << "[" << *pos << "]";
	}
	cout << endl;

	std::list< boost::iterator_range<std::string::iterator> > lis;
	boost::split( lis, str, boost::is_any_of(",.:-+") ); //使用标点分割;
	for ( BOOST_AUTO(pos, lis.begin()); pos != lis.end(); ++pos )
	{
		cout << "[" << *pos << "]";
	}
	cout << endl;

	lis.clear();
	boost::split( lis, str, boost::is_any_of(".:-"), boost::token_compress_on );
	for ( BOOST_AUTO(pos, lis.begin()); pos != lis.end(); ++pos )
	{
		cout << "[" << *pos << "]";
	}
	cout << endl;

	//运行结果;
	// [Zelda][zelda]
	// [Samus][Link][Zelda][][Mario][Luigi][zelda]
	// [Samus,Link] [Zelda] [Mario] [Luigi+zelda]

}

//⑤"、合并
//	join  : 是分割算法的逆运算,它把存储在容器中的字符串连接成一个新的字符串,并且可以指定连接的分隔符.

// join 函数声明如下
template<typename SequenceSequenceT, typename Range1T>
range_value< SequenceSequenceT >::type join( const SequenceSequenceT & Input, const Range1T & Separator );

//join还有一个后缀_if的版本,它接收一个判断式,只有满足判断式的字符串才能参与合并。

{
	//使用list_of需#include <boost\assign\list_of.hpp>
	std::vector<std::string> v = boost::assign::list_of( "Samus" )( "Link" )( "Zelda" )( "Mario" );
	cout << boost::join( v, "+" ) << endl; //合并;

	//定义一个简单的函数对象;
	struct is_contains_a
	{
		bool operator()( const std::string &x )
		{
			return boost::contains( x, "a" );
		}
	};

	cout << boost::join_if( v, "**", is_contains_a() );
}
//程序首先使用assign库向vector添加了四个字符串,然后以 "+" 合并它们。
//随后定义了一个简单的函数对象,它包装了算法contains,判断字符串是否
//包含字符a,最后把这个函数对象作为参数传递给join_if算法。

//运行结果;
//Samus+Link+Zelda+Mario
//Samus**Zelda**Mario

//另:
//查找(分割)迭代器
//	在通用的find_all或split外,string_algo库还提供两个查找迭代器find_iterator和split_iterator,
//它们可以在字符串中像迭代器那样遍历匹配,进行查找或者分割,无需使用容器来容纳.

{
	std::string str( "Samus||samus||mario||||Link" );

	typedef boost::find_iterator<std::string::iterator> string_find_iterator;

	string_find_iterator pos,end;

	for ( pos = boost::make_find_iterator(str, boost::first_finder("samus", boost::is_iequal())); pos != end; ++pos )
	{
		cout << "[" << *pos << "]";
	}
	cout << endl;
	//---------------------------------------------------------------------------------------------------
	typedef boost::split_iterator<std::string::iterator> string_split_iterator;

	string_split_iterator p, endp;
	for ( p = boost::make_split_iterator(str, boost::first_finder("||", boost::is_iequal())); p != endp; ++p )
	{
		cout << "[" << *p << "]";
	}
	cout << endl;

	//运行结果;
	//[Samus][samus]
	//[Samus][samus][mario][][Link]
}
//【注】
//	使用查找迭代器首先要声明迭代器对象find_iterator或split_iterator,它们的模板类型参数是一个迭代器类型a,例如string::iterator或者char*.
//	威力获得迭代器的起始位置,我们需要调用first_finder()函数,它用于判断匹配的对象,然后再用make_find_iterator或make_split_iterator来真正
//创建迭代器。同族的查找函数还有last_finder、nth_finder、token_finder等,它们的含义与查找算法类似,从不同的位置开始查找返回迭代器.
//	初始化工作完成后,我们就可以像使用标准迭代器或者指针那样,不断的遍历迭代器对象,使用解引用操作符获取查找的内容,直到找不到匹配的对象.
//	这里特别注意一下分割迭代器的运用,它可以以任意长度的字符串作为分隔符进行分割,而普通的split算法则只能以字符作为分隔符.


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值