【问题标题】:How do you modify a string splitting function to ignore consecutive delimiters?如何修改字符串拆分函数以忽略连续分隔符?
【发布时间】:2015-03-13 19:44:05
【问题描述】:

我正在使用was posted as an answer on another Stackoverflow question 的函数。然而,发布此消息的用户指出:it does not handle consecutive delimiters

我想知道如何修改它以便它可以处理连续的分隔符?当我有一个额外的分界符时,我想基本上忽略它。

例如说我有这样的事情:

h2,3 d3,4 j3,3 y4,1 g4,3

我想在每个空格处将其拆分为一个字符串数组,但是您可以看到在某些情况下有多个空格。我只是想忽略额外的分隔符。

编辑:为了清楚起见,这是我在上面链接的答案中使用的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

char** str_split(char* a_str, const char a_delim)
{
    char** result    = 0;
    size_t count     = 0;
    char* tmp        = a_str;
    char* last_comma = 0;
    char delim[2];
    delim[0] = a_delim;
    delim[1] = 0;

    /* Count how many elements will be extracted. */
    while (*tmp)
    {
        if (a_delim == *tmp)
        {
            count++;
            last_comma = tmp;
        }
        tmp++;
    }

    /* Add space for trailing token. */
    count += last_comma < (a_str + strlen(a_str) - 1);

    /* Add space for terminating null string so caller
       knows where the list of returned strings ends. */
    count++;

    result = malloc(sizeof(char*) * count);

    if (result)
    {
        size_t idx  = 0;
        char* token = strtok(a_str, delim);

        while (token)
        {
            assert(idx < count);
            *(result + idx++) = strdup(token);
            token = strtok(0, delim);
        }
        assert(idx == count - 1);
        *(result + idx) = 0;
    }

    return result;
}

int main()
{
    char months[] = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";
    char** tokens;

    printf("months=[%s]\n\n", months);

    tokens = str_split(months, ',');

    if (tokens)
    {
        int i;
        for (i = 0; *(tokens + i); i++)
        {
            printf("month=[%s]\n", *(tokens + i));
            free(*(tokens + i));
        }
        printf("\n");
        free(tokens);
    }

    return 0;
}

【问题讨论】:

  • 忽略可能不是正确的方法,具体取决于具体情况。两个连续的分隔符只表示它们之间有一个空字符串。
  • @Havenard 这就是strsep() 的不同之处?使用适当的功能。

标签: c string split delimiter


【解决方案1】:

这应该可以解决问题:

char** str_split(const char *str, char delimiter)
{
    int len, i, j;
    char* buf;
    char** ret;

    len = strlen(str);
    buf = malloc(len + 1);
    memcpy(buf, str, len + 1);

    j = 1;
    for (i = 0; i < len; ++i)
        if (buf[i] == delimiter)
        {
            while (buf[i + 1] == delimiter) i++;
            j++;
        }

    ret = malloc(sizeof(char*) * (j + 1));
    ret[j] = NULL;

    ret[0] = buf;
    j = 1;
    for (i = 0; i < len; ++i)
        if (buf[i] == delimiter)
        {
            buf[i] = '\0';
            while (buf[i + 1] == delimiter) i++;
            ret[j++] = &buf[i + 1];
        }
    return ret;
}

如果您希望禁用序列分隔符溢出,请删除这两行 while (buf[i + 1] == delimiter) i++;

【讨论】:

  • 请问您为什么在输入字符串上使用const
  • @Fogest 表示这个函数可以和字符串字面量一起使用。它不会修改您提供的缓冲区。
【解决方案2】:

在您的 SO 问题中投票率很高的答案是 注意它不处理连续的分隔符“JAN,,,FEB,MAR” - 但不能证实贡献者的评论。

函数strsep() 将连续分隔符视为包含一个空字段,但函数strtok() 确实 忽略分隔符集的多个实例(任意组合)。使用 MSVC,我得到了这个程序

#include<stdio.h>
#include<string.h>

int main(void)
{
    char months[]= "JAN, ,\t   , ,FEB,MAR";
    char seps[] = ", \t\r\n";
    char *sptr;
    sptr = strtok(months, seps);
    while (sptr) {
        printf ("Month is: %s\n", sptr);
        sptr = strtok(NULL, seps);
    }
    return 0;
}

输出:

Month is: JAN
Month is: FEB
Month is: MAR

在您的具体示例中(我怀疑可能包含标签),这将是

#include<stdio.h>
#include<string.h>

int main(void)
{
    char stuff[]= "h2,3      d3,4 j3,3 y4,1 g4,3";
    char seps[] = " \t";
    char *sptr;
    sptr = strtok(stuff, seps);
    while (sptr) {
        printf ("Stuff is: %s\n", sptr);
        sptr = strtok(NULL, seps);
    }
    return 0;
}

输出:

Stuff is: h2,3
Stuff is: d3,4
Stuff is: j3,3
Stuff is: y4,1
Stuff is: g4,3

【讨论】:

  • 所以你是说我应该改用这段代码?因为我试图将每个元素存储到一个数组中。使用我提供的示例数据行,我应该得到一个如下所示的数组:["h2,3", "d3,4", "j3,3", "y4,1", "g4,3"]
  • 添加了您的具体示例。
  • 抱歉,忘记发帖了。
【解决方案3】:

我认为strtok() 能够满足您的要求。来自man page

解析字符串中的两个或多个连续分隔符字节的序列被认为是单个分隔符。

【讨论】:

  • 你看过我实际使用的代码了吗?因为它已经在使用 strtok....
猜你喜欢
  • 2011-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多