如何将字符串拆分为字符串数组?

Jac*_*ack 1 c string split

例如:

输入(字符串): foo $$ foo ## foo []

搜索(串): foo

输出(数组): $$ ,## ,[]

我尝试过这个:

char * str = "foo $$ foo ## foo []";
    char * s = "foo";

    int buf_len = 0;
    int len = strlen(s);
    int i = 0;

    char ** buffer = malloc(MAX_BUFFER_SIZE);
    char * tmpbuf = malloc(MAX_BUFFER_SIZE);
    char * p = str;
    char ** buf = buffer;
    char * tbuf = tmpbuf;

    while(*p)
    {
        if(*p == *s) 
        {
            while(*p == *(s + i)) 
            { 
                i++;
                p++;
            }

            if(i == len) 
            {
                *buf ++ = tbuf;
                memset(tbuf,0,buf_len);
                i = buf_len = 0;
            }
        }
        else 
        {
            *tbuf ++= *p;
            buf_len ++;
        }

        p++;
    }

    *buf ++= NULL;

    int x;
    for(x = 0; buffer[x]; x++)
    {
        printf("%s\n", buffer[x]);
    }

    free(buffer);
    free(tmpbuf);
Run Code Online (Sandbox Code Playgroud)

显示以下输出:

$$ ## []
## []
[]
Run Code Online (Sandbox Code Playgroud)

但预期的是:

$$  
##  
[]
Run Code Online (Sandbox Code Playgroud)

怎么解决这个问题?

Joe*_*ams 5

这是一个将字符串拆分为字符串数组的函数:

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

/*
 * Split a string by a delimiter.
 *
 * This function writes the beginning of each item to @pointers_out
 * (forming an array of C strings), and writes the actual string bytes
 * to @bytes_out.  Both buffers are assumed to be big enough for all of the
 * strings.
 *
 * Returns the number of strings written to @pointers_out.
 */
size_t explode(const char *delim, const char *str,
               char **pointers_out, char *bytes_out)
{
    size_t  delim_length        = strlen(delim);
    char   **pointers_out_start = pointers_out;

    assert(delim_length > 0);

    for (;;) {
        /* Find the next occurrence of the item delimiter. */
        const char *delim_pos = strstr(str, delim);

        /*
         * Emit the current output buffer position, since that is where the
         * next item will be written.
         */
        *pointers_out++ = bytes_out;

        if (delim_pos == NULL) {
            /*
             * No more item delimiters left.  Treat the rest of the input
             * string as the last item.
             */
            strcpy(bytes_out, str);
            return pointers_out - pointers_out_start;
        } else {
            /*
             * Item delimiter found.  The bytes leading up to it form the next
             * string.
             */
            while (str < delim_pos)
                *bytes_out++ = *str++;

            /* Don't forget the NUL terminator. */
            *bytes_out++ = '\0';

            /* Skip over the delimiter. */
            str += delim_length;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

#include <stdio.h>
/* ... */

#define BIG_ENOUGH 1000

int main(void)
{
    char    *items[BIG_ENOUGH];
    char     item_bytes[BIG_ENOUGH];
    size_t   i;
    size_t   count;

    count = explode("foo", "foo $$ foo ## foo []", items, item_bytes);

    for (i = 0; i < count; i++)
        printf("\"%s\"\n", items[i]);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

""
" $$ "
" ## "
" []"
Run Code Online (Sandbox Code Playgroud)

这不会产生您要求的确切输出,因为我不确定您希望如何处理"foo"字符串开头处的周围空格和项目分隔符(在您的示例中)的出现.相反,我模仿了PHP的爆炸功能.


我想指出我的explode功能如何在内存管理上发挥作用.由调用者决定缓冲区是否足够大.这对于快速脚本来说很好,但在一个更严肃的程序中可能会很烦人,你需要做一些数学运算才能正确使用这个函数.我本可以编写一个更"强大"的实现来执行自己的分配,但是:

  • 这会使实施变得混乱.

  • 它不会给调用者提供使用自己的内存分配器的选项.

所以实现explode我的方式是"糟糕的",因为它很难正确使用,更糟糕的是,使用方法不正确.另一方面,它是"好"的,因为它分离了功能和内存管理的关注点.