使用多个char作为分隔符拆分字符串

时间:2016-08-11 14:26:08

标签: c string split

假设我有一个字符串"file1.h: file2.c,file3.cpp",我希望将其拆分为"file1.h""file2.c,file3.cpp" - 即使用::和空格)作为分隔符。我该怎么办?

我在没有帮助的情况下尝试了这段代码:

int main(int argc, char *argv[]) {
   char str[] = "file1.h: file2.c,file3.cpp";
   char name[100];
   char depends[100];
   sscanf(str, "%s: %s", name, depends);
   printf("Name: %s\n", name);
   printf("Deps: %s\n", depends);
}

我得到的输出是:

  

姓名:file1.h:

     

的DEP:

4 个答案:

答案 0 :(得分:2)

您似乎需要的是strtok()。在man page中了解相关信息。来自C11的相关引用,章节§7.24.5.8

  

strtok函数的一系列调用将s1指向的字符串分成一个   标记序列,每个标记由指向的字符串中的字符分隔   按s2 。 [...]

在您的情况下,您可以使用像

这样的分隔符
  char * delim = ": "; //combination of : and a space

去完成工作。

另外值得一提的是,

  • 输入需要为strtok()
  • 进行修改(在您的情况下)
  • 它实际上会破坏输入的输入,如果你以后需要实际的话,请保留一份副本。

答案 1 :(得分:1)

正如Sourav所说,你真的需要使用strtok来标记字符串。但是,这并不能解释为什么您的现有代码无效。

答案在于sscanf的规范以及它如何处理格式字符串中的'%s'

来自man页面:

  

s匹配一系列非空白字符;

因此,格式字符串中冒号空格的存在与计算第一个'%s'无关。当sscanf看到第一个%s时,它只会消耗输入字符串,直到遇到空白字符,为您提供name "file1.h:"的值(请注意包含冒号) )。

接下来,它会尝试处理格式字符串中的冒号空间序列。

再次,从man页面

  

格式字符串由一系列指令组成,这些指令描述了如何处理输入字符序列。

冒号空间序列与任何已知指令都不匹配(即"%"后跟某些内容),因此会出现匹配失败。

如果您的格式字符串只是"%s%s",那么sscanf几乎可以让您获得所需内容。

int main(int argc, char *argv[]) {
   char str[] = "file1.h: file2.c,file3.cpp";
   char name[100];
   char depends[100];
   sscanf(str, "%s%s", name, depends);
   printf("str: '%s'\n", str);
   printf("Name: %s\n", name);
   printf("Deps: %s\n", depends);
   return 0;
}

这给出了这个输出:

str: 'file1.h: file2.c,file3.cpp'
Name: file1.h:
Deps: file2.c,file3.cpp

此时,您可以简单地检查sscanf返回值是否为2(即找到两个值),name的最后一个字符是冒号。然后截断name即可得到答案。

当然,按照这种逻辑,您无法使用sscanfdepends变量解析为多个字符串......这就是为什么其他人建议使用{ {1}},strtok等,因为您正在解析和标记您的输入。

答案 2 :(得分:1)

这是另一种方法,它使用strchr(),但这假设输入字符串始终具有格式

name: item1,item2,item3,...,itemN

这是程序

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

int
main(void)
{
    const char *const string = "file1.h: file2.c,file3.cpp ";

    const char *head;
    const char *tail;
    const char *next;

    // This basically makes a pointer to the `:'
    head = string;  
    // If there is no `:' this string does not follow
    // the assumption that the format is
    //
    //    name: item1,item2,item3,...,itemN
    //    
    if ((tail = strchr(head, ':')) == NULL)
        return -1;
    // Save a pointer to the next character after the `:'
    next = tail + 1;
    // Strip leading spaces
    while (isspace((unsigned char) *head) != 0)
        ++head;
    // Strip trailing spaces
    while (isspace((unsigned char) *(tail - 1)) != 0)
        --tail;     

    fputc('*', stdout);
    // Simply print the characters between `head' and `tail'
    // you could as well copy them, or whatever
    fwrite(head, 1, tail - head, stdout);
    fputc('*', stdout);
    fputc('\n', stdout);

    head = next;
    while (head != NULL) {      
        tail = strchr(head, ',');
        if (tail == NULL) {
            // This means there are no more `,'
            // so we now try to point to the end
            // of the string
            tail = strchr(head, '\0');
        }
        // This is basically the same algorithm
        // just with a different delimiter which
        // will presumably be the same from
        // here
        next = tail + 1;
        // Strip leading spaces
        while (isspace((unsigned char) *head) != 0)
            ++head;
        // Strip trailing spaces
        while (isspace((unsigned char) *(tail - 1)) != 0)
            --tail;     
        // Here is where you can extract the string
        // I print it surrounded by `*' to show that
        // it's stripping white spaces
        fputc('*', stdout);
        fwrite(head, 1, tail - head, stdout);
        fputc('*', stdout);
        fputc('\n', stdout);
        // Try to point to the next one
        // or make head `NULL' if this is
        // the end of the string
        //
        // Note that the original `tail' pointer
        // that was pointing to the next `,' or
        // the end of the string, has changed but
        // we have saved it's original value
        // plus one, we now inspect what was
        // there
        if (*(next - 1) == '\0') {
            head = NULL;
        } else {
            head = next;
        }
    }
    fputc('\n', stderr);
    return 0;
}

它过分评论指导读者。

答案 3 :(得分:0)

好吧,我已经很晚了。我对C中的内置函数知之甚少。所以我开始为你编写一个解决方案。我认为你现在不需要这个。但是,无论如何here it is并根据您的需要进行修改。如果您发现任何错误,请随时告诉。