欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++ strtok()无法截取连续两个分隔符之间的空字符串, 解决方法

程序员文章站 2022-03-11 18:05:53
...

前言

  • 问题描述:
    与前台约定按顺序解析对应信息, 如果中间出现空数据(或者出现连续两个分隔符), strtok就会出问题.

看下面这个例子:

  1 #include <string.h>
  2 #include <stdio.h>
  3 
  4 int main()
  5 {
  6     char str[] = "abc||de|fghi";
  7 
  8     char* p = strtok(str, "|");
  9     for(int i = 0; p != NULL; ++i)
 10     {
 11         printf("substr[%d]:%s\n", i, p);
 12         p = strtok(NULL, "|");
 13     }
 14 
 15     return 0;
 16 }

源字符串为:”abc||de|fghi”
分隔符为: ‘|’
运行结果为:
C++ strtok()无法截取连续两个分隔符之间的空字符串, 解决方法

中间abc与de之间的连续两个’|’, strtok在分隔的时候, 直接把空字符串跳过了,
而有的时候, 即使分隔符间是空字符串, 我们也是需要获取的;
那么此时strtok就无法满足需要了, 下面是我用c++实现的, 可以截取空串的方法.

方法介绍

#include <stdio.h>
#include <string>
#include <vector>
/*
名称:my_split(const std::string& src, const char& delim,
         std::vector<std::string>& vec)

功能:用分隔符将源字符串分隔为多个子串并传出; n个分隔符, 分n+1个子串


参数:
     src-传入参数, 源字符串;
     delim-传入参数, 分隔符;
     vec-传出参数, 子串的集合;

返回值:
    0-成功;
    其它-失败;
 */

int my_split(const std::string& src, const char& delim,
        std::vector<std::string>& vec)
{
    int src_len = src.length();
    int find_cursor = 0;
    int read_cursor = 0;

    if (src_len <= 0) return -1;

    vec.clear();
    while (read_cursor < src_len){

        find_cursor = src.find(delim, find_cursor);

        //1.找不到分隔符
        if (-1 == find_cursor){
            if (read_cursor <= 0) return -1;

            //最后一个子串, src结尾没有分隔符
            if (read_cursor < src_len){
                vec.push_back(src.substr(read_cursor, src_len - read_cursor));
                return 0;
            }
        }
        //2.有连续分隔符的情况
        else if (find_cursor == read_cursor){
            //字符串开头为分隔符, 也按空子串处理, 如不需要可加上判断&&(read_cursor!=0)
            vec.push_back(std::string(""));
        }
        //3.找到分隔符
        else
            vec.push_back(src.substr(read_cursor, find_cursor - read_cursor));

        read_cursor = ++find_cursor;
        if (read_cursor == src_len){
            //字符串以分隔符结尾, 如不需要末尾空子串, 直接return
            vec.push_back(std::string(""));
            return 0;
        } 
    }//end while()

    return 0;
}

调用

int main(int argc, char* argv[])
{
    std::vector<std::string> vecSrc;
    std::vector<std::string> vecSplit;

    vecSrc.push_back(std::string("|Hello||world|"));
    vecSrc.push_back(std::string("Hello||world"));

    for (auto src : vecSrc){
        int iRet = my_split(src, '|', vecSplit);
        if (0 == iRet){
            printf("src:%s, vecSplit.size():%d\n", src.c_str(), vecSplit.size());

            int idex = 0;
            for (auto it : vecSplit)
                printf("vec[%d]:%s\n", idex++, it.c_str());
        }
        printf("---------------------------------\n");
    }

    return 0;
}

运行结果:
C++ strtok()无法截取连续两个分隔符之间的空字符串, 解决方法

可以看到, Hello和World之间的空字符串, 也能通过分隔符截取出来了.
如果开头或结尾有分隔符, 会将开头或结尾处都截出空子串,
类似刀切割绳子, 即:n个分隔符, 必有n+1个子串;
若不需要开头和结尾分隔子串, 可参照注释修改两行代码即可.

结语

上述方法比strtok有以下优点:

  • 没有用到static变量, 故线程安全;
  • 传入源字符串为const引用, 不会改变源字符串;
  • 可以截取到连续分隔符间的空串;
  • 如果首次未找到分隔符将会返回失败, 而strtok会返回源字符串

如有不足, 望不吝赐教, 感谢!