根据标识符分割字符串
常常遇到根据某个标识符分割字符串,并将分割的结果保存到字符串数组中。遇到过以下几种需求:
- 分隔符是一个字符集和,以便处理不同的输入格式,比如用tab或逗号分隔的输入
- 处理2个分隔符之间的内容为空的情况,2种需求,输出空字符串或者忽略掉
- 处理字符串末尾的回车符,2种需求,忽略或删除
c语言的strtok函数支持分割字符串,它在遇到分隔符之间的内容为空的时候会忽略掉空元素,往前推进返回下个非空的字符串,分割完成后返回NULL。这个函数貌似还有个多线程的版本。
//分割字符串,如果遇到分割的结果是空字符串也作为输出。
//substr(begin,offset)在begin非法、offset为0或过大的情况返回空字符串
void split1(const string& str)
{
std::vector<string> splitStr;
char* separator="\t,";
string::size_type begin=0;
string::size_type nextPos;
do{
nextPos = str.find_first_of(separator,begin);
//即使substr返回空字符串也记录
splitStr.push_back(str.substr(begin,nextPos-begin));
begin = nextPos+1;
}while(nextPos != string::npos);
//去掉最后的换行符
if(splitStr.size()>0){
string& lastEle = splitStr.back();
if(lastEle.size()>0 && *(lastEle.end()-1)=='\n')
{
lastEle.erase(lastEle.end()-1);
}
}
for(size_t i=0; i < splitStr.size();++i)
{
printf("case1 idx=%d, len=%d, s=%s\n",i,splitStr[i].size(),splitStr[i].c_str());
}
}
//分割字符串,跳过空字符串。
void split2(string& strCellCfg)
{
std::vector<string> splitStr;
char aucTmp[500];
strcpy(aucTmp,strCellCfg.c_str());
const char* separator = "\t,";
//tok函数会跳过“a,,b”分隔符中间的空字符串;且如果找不到被分割的内容,则返回空,比如“,”
//所以以下实现产生的结果中不会包含空字符串
char* pToke = strtok(aucTmp,separator);
while(pToke!=NULL)
{
splitStr.push_back(pToke);
pToke = strtok(NULL,separator);
}
if(splitStr.size()>0){
string& lastEle = splitStr.back();
if(lastEle.size()>0 && *(lastEle.end()-1)=='\n')
{
lastEle.erase(lastEle.end()-1);
}
}
for(size_t i=0; i < splitStr.size();++i)
{
printf("case2 idx=%d, len=%d, s=%s\n",i,splitStr[i].size(),splitStr[i].c_str());
}
}
void testSplit()
{
string t[]={"1,2,3", "1 2 3",
"h\n",
"",
",",
",,",
"a,"};
for(int i=0; i < 7; ++i)
{
split1(t[i]);
split2(t[i]);
}
}
//substr(begin,offset)在begin非法、offset为0或过大的情况返回空字符串
void split1(const string& str)
{
std::vector<string> splitStr;
char* separator="\t,";
string::size_type begin=0;
string::size_type nextPos;
do{
nextPos = str.find_first_of(separator,begin);
//即使substr返回空字符串也记录
splitStr.push_back(str.substr(begin,nextPos-begin));
begin = nextPos+1;
}while(nextPos != string::npos);
//去掉最后的换行符
if(splitStr.size()>0){
string& lastEle = splitStr.back();
if(lastEle.size()>0 && *(lastEle.end()-1)=='\n')
{
lastEle.erase(lastEle.end()-1);
}
}
for(size_t i=0; i < splitStr.size();++i)
{
printf("case1 idx=%d, len=%d, s=%s\n",i,splitStr[i].size(),splitStr[i].c_str());
}
}
//分割字符串,跳过空字符串。
void split2(string& strCellCfg)
{
std::vector<string> splitStr;
char aucTmp[500];
strcpy(aucTmp,strCellCfg.c_str());
const char* separator = "\t,";
//tok函数会跳过“a,,b”分隔符中间的空字符串;且如果找不到被分割的内容,则返回空,比如“,”
//所以以下实现产生的结果中不会包含空字符串
char* pToke = strtok(aucTmp,separator);
while(pToke!=NULL)
{
splitStr.push_back(pToke);
pToke = strtok(NULL,separator);
}
if(splitStr.size()>0){
string& lastEle = splitStr.back();
if(lastEle.size()>0 && *(lastEle.end()-1)=='\n')
{
lastEle.erase(lastEle.end()-1);
}
}
for(size_t i=0; i < splitStr.size();++i)
{
printf("case2 idx=%d, len=%d, s=%s\n",i,splitStr[i].size(),splitStr[i].c_str());
}
}
void testSplit()
{
string t[]={"1,2,3", "1 2 3",
"h\n",
"",
",",
",,",
"a,"};
for(int i=0; i < 7; ++i)
{
split1(t[i]);
split2(t[i]);
}
}
测试结果:
case1 idx=0, len=1, s=1
case1 idx=1, len=1, s=2
case1 idx=2, len=1, s=3
case2 idx=0, len=1, s=1
case2 idx=1, len=1, s=2
case2 idx=2, len=1, s=3
case1 idx=0, len=1, s=1
case1 idx=1, len=1, s=2
case1 idx=2, len=1, s=3
case2 idx=0, len=1, s=1
case2 idx=1, len=1, s=2
case2 idx=2, len=1, s=3
case1 idx=0, len=1, s=1
case1 idx=1, len=1, s=2
case1 idx=2, len=1, s=3
case2 idx=0, len=1, s=1
case2 idx=1, len=1, s=2
case2 idx=2, len=1, s=3
case1 idx=0, len=1, s=h
case2 idx=0, len=1, s=h
case1 idx=0, len=0, s=
case1 idx=0, len=0, s=
case1 idx=1, len=0, s=
case1 idx=0, len=0, s=
case1 idx=1, len=0, s=
case1 idx=2, len=0, s=
case1 idx=0, len=1, s=a
case1 idx=1, len=0, s=
case2 idx=0, len=1, s=a