在boost的字符串算法中,关于分割的函数应该是有2个的,还记得我们在115讲里面说到的find_all吗?从某些角度来说这也算是一种分割方式,只是这比较特殊一些,所有的结果都是一样的而已,那么这一讲我们来说一个一般的分割,其实关于分割大家都比较清楚的了,简单点说就是将一个字符串按照某种方式将他分成N多段,这种对字符串的操作通常很有用,在实际项目中对字符串的处理可以说是随处可见,而分割字符串更是家常便饭了,那么说了这么多废话,我们来点实际的东西。
//==========================================
template<typename SequenceSequenceT, typename RangeT, typename PredicateT >
inline SequenceSequenceT&
split(
SequenceSequenceT&
Result,
RangeT&
Input,
PredicateT Pred,
token_compress_mode_type eCompress=token_compress_off )
//==========================================
这就是split的函数声明,SequenceSequenceT可以是vector,deque,list等标准容器,对Input的要求也没那么多,通常于我们来说只要是string或者是boost::iterator_range<std::string::iterator>即可,当然我们通常都是对string进行处理的,所以这我们就不关心了,PredicateT是一个判断式,可以理解为一个函数对象,因为这里是当以当前字符为参数时返回true的话那么当前点就是一个分割点,我们不用纠结这东西,boost本身就提供有一个已经很完备的判断式了:is_any_of,我们只需要将我们要分割的东西给他就行,看下面的例子就知道。在结果中分割字符串是要被丢弃的。token_compress_mode_type 这个参数的目的简单点说就是这种形式 :: ,这里是当作两个:号来处理呢还是就是:号来处理?嗯,这句话说得不清不楚,还好在程序有时候比语言的表述来更直接一些:
//=========================================
string str("
Hello :::::: World"
);
vector<string>result;
split(result,str,is_any_of("
:"
));
// 使用空格和:来进行分割
// 这里会得到结果是 "
Hello"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
World"
result.clear();
split(result, str, is_any_of("
:"
),token_compress_on);
// 使用空格和:进行分割
// result : "
Hellow"
"
World"
//========================================
还是代码来得实在一些,简单两句代码就将一些于我来说很难用语言来描述的现象给解释清楚了,从上面的函数原型里面我们看到split的最后一个参数是有默认值的,那就是token_compress_off,这就是不压缩处理,而我们开启压缩处理后,那些:::::都被当成一个:,有因为空格和:都是连在一起的,而空格也是被定义为分隔符,所以也都被压缩在一起进行处理了。于是乎我们就得到了想要的Hellow World了。
和split相对的是join,顾名思义,这就是将字符串连接起来,所以他的用法很简单,不过他有两个版本,一个带有_if后缀的版本,这自然是需要一个判断式,只有满足判断式的字符串才会被添加到链接队列之中,我们来看看他们的用法:
//==========================================
std::string str("
Hello,World,Ni,Hao,A"
);
std::vector<std::string>v_str;
boost::algorithm::split(v_str, str, boost::algorithm::is_any_of("
,"
),boost::algorithm::token_compress_on);
// 将字符串按照,号进行分割
std::string __str = boost::algorithm::join(v_str, "
—"
);
// 再将字符串重新连接起来
// Hello—World—Ni—Hao–A
std::string __str2 = boost::algorithm::join_if(v_str, "
—"
, [&
](const std::string&
s){
return boost::algorithm::contains(s, "
l"
);
});
// 只连接包含l字符的字符串
// 结果为Hello—World
//=========================================
不论是split还是join,他们都是对字符串进行处理,那么很多时候我们可能想要的不是字符串,有可能是其他的东西,比如是数字等等,为了解决这个问题,我们可以对split和join进行扩展(可以参考我们前面说的MString,他们可以转变为任意类型的东西)。
//========================================
template<typename T,typename A,template<typename T1,typename A1>class C>
void __split(C<T, A>&
result, const std::string&
input,const std::string&
spliter,bool isPress = false){
result.clear();
if (input.empty())
return;
std::vector<std::string>__result;
boost::algorithm::token_compress_mode_type __type;
if (isPress)
__type = boost::algorithm::token_compress_on;
else
__type = boost::algorithm::token_compress_off;
boost::algorithm::split(__result, input, boost::is_any_of(spliter), __type);
for (auto&
t : __result){
try{
T __t = boost::lexical_cast<T>(t);
result.push_back(__t);
}
catch (boost::bad_lexical_cast e){
;
}
}
}
//=================================
// 针对string进行特化
//=================================
template<typename A, template<typename T1, typename A1>class C>
void __split(C<std::string, A>&
result, const std::string&
input, const std::string&
spliter, bool isPress = false){
result.clear();
if (input.empty())
return;
std::vector<std::string>__result;
boost::algorithm::token_compress_mode_type __type;
if (isPress)
__type = boost::algorithm::token_compress_on;
else
__type = boost::algorithm::token_compress_off;
boost::algorithm::split(result, input, boost::is_any_of(spliter), __type);
}
template<class T,class A,template<class T1,class A1>class C>
std::string __join(const C<T, A>&
Input, const std::string&
joiner){
std::vector<std::string>__v_str;
for (auto&
c : Input){
try{
std::string str = boost::lexical_cast<std::string>(c);
__v_str.push_back(str);
}
catch (boost::bad_lexical_cast e){
;
}
}
return boost::join(__v_str, joiner);
}
//==================================================
// 同样需要针对string进行特化
//==================================================
template<class A, template<class T1, class A1>class C>
std::string __join(const C<std::string, A>&
Input, const std::string&
joiner){
return boost::join(Input, joiner);
}
//=========================================================
现在使用起来就变得相对简单了:
//=========================================================
int main(){
std::string str("
hello,World,Ni,Hao,A"
);
std::vector<std::string>v_str;
__split(v_str, str, "
,"
);
std::cout <<"
===============split=============="
<<std::endl;
for (auto &
v : v_str){
std::cout <<v <<std::endl;
}
std::string __str = __join(v_str, "
—"
);
std::cout <<"
================join============="
<<std::endl;
std::cout <<__str <<std::endl;
std::string __str2 = boost::algorithm::join_if(v_str, "
—"
, [&
](const std::string&
s){
return boost::algorithm::contains(s, "
l"
);
});
std::cout <<"
===========join if=================="
<<std::endl;
std::cout <<__str2 <<std::endl;
str = "
Hello :::::: World"
;
v_str.clear();
boost::algorithm::split(v_str, str, boost::algorithm::is_any_of("
:"
),boost::algorithm::token_compress_on);
str = ("
123,345,981,3345,98"
);
std::vector<int>v_int;
__split(v_int, str, "
,"
);
std::cout <<"
=========split for int============"
<<std::endl;
for (auto&
v : v_int){
std::cout <<v <<std::endl;
}
std::string str3 = __join(v_int, "
—"
);
std::cout <<"
========join for int============"
<<std::endl;
std::cout <<str3 <<std::endl;
return 0;
}
//=====================================================
关于join_if的扩展就留给大家当是练习吧。
转眼间,我们的编程教室都已经两年了,只是今年好像都一直比较忙,所以更新得不多,但是会坚持下去,谢谢大家的一直支持,新的一年里,大家共勉。
//===================================================
回复D或者d查看目录,回复阿拉伯数字查看相应章节。
原文始发于微信公众号(
C/C++的编程教室
):第117讲 boost::algorithm::string之分割与合并
|