字符串分割函数StringTokenizer与strtok,strsep的比较

简介: 字符串分割在我们在开发过程中经常遇到的问题。根据一个标记串,将输入的字符串分割成多个子串。实际编码当中,我们发现使用不同的函数得到的结果也会有区别。 为了方便比较,我们定义一个统一的输入输出比较方式:vector<string> parsetoken(const string &str, const string& delim); 输入源字


字符串分割在我们在开发过程中经常遇到的问题。根据一个标记串,将输入的字符串分割成多个子串。实际编码当中,我们发现使用不同的函数得到的结果也会有区别。
为了方便比较,我们定义一个统一的输入输出比较方式:
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则不会过滤空字符串

相关文章
|
14天前
字符串反转
【6月更文挑战第18天】字符串反转。
6 1
|
2月前
|
存储 安全 算法
做50个Java字符串题即精通字符串
字符串常量池是 Java 堆内存的一个特殊存储区域,用于存储字符串字面量和字符串常量。Java 虚拟机为了节省内存空间和提高效率,会确保所有的字符串字面量只包含一份,这样如果有多个引用指向相同的字面量,它们实际上会指向内存中相同的位置。字符串不可变性意味着一旦字符串对象被创建,它所包含的字符序列就不能被更改。Java 中的String对象是不可变的,因为不可变性可以提供编译时的优化、线程安全性,以及因为字符串常量池而更好的内存效率。
113 0
|
2月前
|
C++
大小写转换——islower/isupper或者tolwer/toupper函数的用法
大小写转换——islower/isupper或者tolwer/toupper函数的用法
25 0
|
12月前
撕碎字符串反转【C】
首先我们对题目进行分析,反转字符串就是将数组中的元素位置进行互换从而达到效果,但是当我们对字符串前后进行互换时,会出现”.gnijieb ekil I"这与我们预先的目标不一致,这个题就特殊在这里。我们要进行二次交换,对字符串中的每个单词进行交换,把每一个单词看作一个整体在进行一次数组交换即可。
49 0
|
12月前
|
索引
分割字符串的方法
分割字符串的方法
74 0
字符串函数_strtok()
strtok是用来切割字符串的,引用头文件为#include<string.h> strtok函数的声明:
详解比较古怪的字符串拆分函数:strtok函数
详解比较古怪的字符串拆分函数:strtok函数
144 0
详解比较古怪的字符串拆分函数:strtok函数
C/C++编程题之字符串反转
C/C++编程题之字符串反转
|
算法 Java C语言
字符串——28. 实现 strStr()
本专栏按照数组—链表—哈希—字符串—栈与队列—二叉树—回溯—贪心—动态规划—单调栈的顺序刷题,采用代码随想录所给的刷题顺序,一个正确的刷题顺序对算法学习是非常重要的,希望对大家有帮助