C++移除序列中连续重复的特定值示例代码
前言
最近在写YTL中的字符串相关辅助函数。实现到split函数时,希望能够实现类似Python当中的str.split方法的功能。
IfsepisnotspecifiedorisNone,adifferentsplittingalgorithmisapplied:runsofconsecutivewhitespaceareregardedasasingleseparator,andtheresultwillcontainnoemptystringsatthestartorendifthestringhasleadingortrailingwhitespace.
也就是说,在最基本的split的基础上,要添加两个功能:
•删除输入字符串首尾的空白;
•将字符串中的连续分隔符当成一个分隔符看待。
前一个功能很好实现。将空白符保存在constchar*trim_chars="\t\n\r\v\f"当中,然后使用std::string::find_first_not_of以及std::string::find_last_not_of即可找到有效内容的起止位置,最后再std::string::erase一下就好了。
后一个功能也不复杂。但要写得优雅——最好是能利用上标准库的设施——就不那么容易了。
std::unique的基本用法
std::unique是定义在algorithm头文件内的容器算法。它有两种基本形式:
templateForwardItunique(ForwardItfirst,ForwardItlast); template ForwardItunique(ForwardItfirst,ForwardItlast,BinaryPredicatep);
其中,第一种形式是第二种形式的特例,它等价于BinaryPredicatep为连续两元素相等性判断时的第二种形式:
template::value_type&, consttypenamestd::iterator_traits ::value_type&)> ForwardItunique(ForwardItfirst,ForwardItlast, BinaryPredicatep=[](consttypenamestd::iterator_traits ::value_type&lhs, consttypenamestd::iterator_traits ::value_type&rhs){ returnlhs==rhs;});
这也就是说,第一种形式的std::unique会找到每个连续重复的区间,而后保留这些区间的首个元素,最后返回新序列逻辑上的尾后迭代器。例如,aabbccaa经过std::unique处理之后得到:
abca????
↑
这里用箭头标出的位置,即是std::unique的返回值所指向的位置。需要注意的是,经过std::unique处理之后,容器的实际大小没有发生改变,甚至逻辑尾后迭代器到容器实际尾后迭代器之间的左闭右开区间内的迭代器仍然是可解引用的(dereferenceable)。但这部分区间内的元素的值是不确定的。因此,在使用std::unqiue之后,往往会调用容器的erase函数成员,删除逻辑尾后迭代器开始的所有元素。例如:
//#include//#include std::stringsource("aabbccaa"); source.erase(std::unique(source.begin(),source.end()),source.end()); std::cout< 只对特定内容进行std::unique操作
回到最开始的问题。我们需要的功能,是针对分隔符sep进行操作,将连续出现的sep压缩成一个。std::unique的默认行为则不然,它会将所有连续出现的元素都压缩成一个——不光是sep。为此,我们需要实现自己的BinaryPredicate。首先,由于我们要指定具体需要被std::unique压缩的元素,我们必然要将其作为函数参数传入函数。于是我们有以下实现:
//#includetemplate boolAreConsecutiveElements(constT&target,constT&lhs,constT&rhs){ return(lhs==rhs)and(lhs==target); } std::unique要求一个二元谓词(BinaryPredicate),但此处我们实现的是三元谓词。于是,好在target总是应当预先给出的,所以我们可以利用std::bind将target绑定在AreConsecutiveElements的第一个参数上,产生一个二元谓词。
//#include//usingnamespacestd::placeholders; //#include //#include constchartarget='b' autobinp=std::bind(AreConsecutiveElements,target,_1,_2); std::stringsource("aabbccaa"); source.erase(std::unique(source.begin(),source.end(),binp),source.end()); std::cout< 这里,我们将'b'作为压缩目标,并将其与AreConsecutiveElements绑定在一起,产生一个新的二元谓词。最终输出期待的结果。
附:std::unique的一个可能实现
templateForwardItunique(ForwardItfirst,ForwardItlast,BinaryPredicatep){ if(first==last){ returnlast; } ForwardItresult=first; while(++first!=last){ if(!p(*result,*first)&&++result!=first){ *result=std::move(*first); } } return++result; } 总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。