字符串分割函數StringTokenizer與strtok,strsep的比較
字符串分割在我們在開發過程中經常遇到的問題。根據一個標記串,將輸入的字符串分割成多個子串。實際編碼當中,我們發現使用不同的函數得到的結果也會有區別。
為了方便比較,我們定義一個統一的輸入輸出比較方式: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則不會過濾空字符串
最後更新:2017-04-03 05:39:47