字符串分割在我们在开发过程中经常遇到的问题。根据一个标记串,将输入的字符串分割成多个子串。实际编码当中,我们发现使用不同的函数得到的结果也会有区别。
为了方便比较,我们定义一个统一的输入输出比较方式:
vector<string> parsetoken(const string &str, const string& delim);
输入源字符串str
,分割标记串为delim
,分割的子串保存到vector<string>
中。
我们分别使用内部的StringTokenizer::parseTokens,与c语言中的strtok,strtep函数来实现我们上面这个标准输入输出函数。
StringTokenizer::parseTokens的定义与上面的定义相同,无需改动直接使用。
使用strtok实现parsetoken如下:
vector<string> parsetoken_2(const string &str,const string &delim)
{
vector<string> values;
char *result = NULL;
char *buf = new char[str.length()+1];
strcpy(buf,str.c_str());
result = strtok( buf, delim.c_str());
while( result != NULL ) {
values.push_back(string(result));
result = strtok( NULL, delim.c_str());
}
delete buf;
return values;
}
使用strtep实现parsetoken如下:
vector<string> parsetoken(const string &str,const string &delim)
{
vector<string> values;
char *result = NULL;
char *buf = new char[str.length()+1];
strcpy(buf,str.c_str());
result = strsep( &buf, delim.c_str());
while( result != NULL ) {
values.push_back(string(result));
result = strsep( &buf, delim.c_str());
}
delete buf;
return true;
}
使用的测试字符串为"|5111999991|普通-通票测试(ZTY)|||11900|10171|1729|0.17|
";
测试函数为:
int TestApp::MainProcess()
{
string str2="|5111999991|普通-通票测试(ZTY)|||11900|10171|1729|0.17|";
cout<<"test string:"<<str2<<endl;
cout<<"\n-----use StringTokenizer---------"<<endl;
vector<string> vec0 = StringTokenizer::parseTokens(str2,"|");
cout<<"vec0.size="<<vec0.size()<<endl;
for(int i=0;i<vec0.size();++i){
printf("%d:%s\n",i,vec0[i].c_str());
}
cout<<"\n-----use strtok---------"<<endl;
vector<string> vec1=parsetoken_2(str2,"|");
cout<<"vec1.size="<<vec1.size()<<endl;
for(int i = 0 ;i< vec1.size(); ++i){
printf("%d:%s\n",i,vec1[i].c_str());
}
cout<<"\n-----use strsep---------"<<endl;
vector<string> vec2=parsetoken(str2,"|");
cout<<"vec2.size="<<vec2.size()<<endl;
for(int i = 0 ;i< vec2.size(); ++i){
printf("%d:%s\n",i,vec2[i].c_str());
}
return 0;
}
我们将分割后子串的个数以及每个子串打印出来,对比结果如下:
test string:|5111999991|普通-通票测试(ZTY)|||11900|10171|1729|0.17|
-----use StringTokenizer---------
vec0.size=6
0:5111999991
1:普通-通票测试(ZTY)
2:11900
3:10171
4:1729
5:0.17
-----use strtok---------
vec1.size=6
0:5111999991
1:普通-通票测试(ZTY)
2:11900
3:10171
4:1729
5:0.17
-----use strsep---------
vec2.size=10
0:
1:5111999991
2:普通-通票测试(ZTY)
3:4:
5:11900
6:10171
7:1729
8:0.17
9:
结果分析
StringTokenizer和strtok的结果是一样的,而strsep则出现了一些空字符串,也就是"\0"
.而前两个则将"\0"
作为无意义的子串过滤掉了。
1.如果空字符串"\0"
是无意义的,则过滤是可以接受的。
2.如果空字符串"\0"
是有意义的,则过滤是错误的。
假设有一个结构体Student:
struct Student
{
string name;
string sex;
string age;
};
要将一个字符串"xiaoming||20"
按|
分割到一个Student结构体里,现在,中间的空字符串是有意义的,表示结构体里的sex,不能被过滤。这时候就不能使用内部的StringTokenizer来分割字符串了。最好使用strsep来实现对应的分割函数。
strtok不是一个线程安全的函数,会被逐渐废弃,请使用strtok_r或者strsep代替。
总结
StringTokenizer,strtok,trsep都用于分割字符串。
- StringTokenizer和strtok都会主动过滤掉空字符串
- strsep则不会过滤空字符串
字符串分割函数StringTokenizer与strtok,strsep的比较