【问题标题】:String manipulation using strtok/ sscanf in C在 C 中使用 strtok/sscanf 进行字符串操作
【发布时间】:2013-08-17 20:42:42
【问题描述】:

我正在尝试将以下字符串分成三个单独的变量,即 a、b 和 c。:

"   mov/1/1/1,0 STR{7}, r7" 

每个需要持有不同的字符串段,例如:

a = "mov/1/1/1,0"
b = "STR{7}"
c = "r7"

每个命令之间可能有空格或制表符;这就是这部分代码更棘手的原因。

我尝试使用strtok 进行字符串操作,但没有成功。

char command[50] = "    mov/1/1/1,0 STR{7}, r7";
char a[10], b[10], c[10];
char * ptr = strtok(command, "\t");
strcpy(a, ptr);
ptr = strtok(NULL, "\t");
strcpy(b, ptr);
ptr = strtok(NULL, ", ");
strcpy(c, ptr);

但这会让事情变得非常混乱,因为变量a, bc 持有的值超出了它们应有的值,这会导致程序崩溃。

输入可能会有所不同:

"   mov/1/1/1,0 STR{7}, r7"
"jsr /0,0            PRTSTR"
"mov/1/1/0,0         STRADD{5}, LASTCHAR {r3} "

其中 a、b 和 c 的值更改为给定字符串的不同部分。

有人告诉我,将 sscanf 用于这种方式比使用 strtok 更安全,但我不确定它为什么以及如何帮助我。

很高兴听到您的意见!

【问题讨论】:

  • mov/1/1/0,0LASTCHAR {r3} 会超过九个字符(a[10],c[10])。
  • 您说您希望用“空格或制表符”分隔事物,但随后您使用 strtok 并仅将 "\t" 作为分隔符。也许您只想要" \t"(如您所说的空格或制表符),尽管这将采用一个或多个空格或制表符的任何序列作为分隔符。如果你想让两个空格表示一个“空”字段,那是行不通的。
  • 您的示例字符串"jsr /0,0 PRTSTR" 会在工作中使用扳手;它在第二个字段中有一个重要的逗号,而在其他两个示例字符串中,第二个字段中的逗号不重要。如果您需要删除尾随逗号,您可以在基于空格的拆分之后执行此操作。

标签: c strtok scanf


【解决方案1】:

这应该可以解决问题:

sscanf(command, "%s,%s,%s", &a, &b, &c)

从 scanf 手册页,%s 吃空格,无论是空格还是制表符:

s :匹配一系列非空白字符;下一个指针 必须是一个指向字符数组的指针,它的长度足以容纳 输入序列和终止的空字节('\0'),它被添加 自动地。输入字符串在空白处或在 最大字段宽度,以先到者为准。

【讨论】:

  • 这包括第二个字符串中的尾随逗号,这似乎不是 OP 的预期目标。也许更新您的格式规范以解决这个问题。
  • 谢谢,它在某些情况下起到了作用,但在其他情况下,每个短语之间可能存在制表符或空格,导致 sscanf 无法正确读取。此外,在第二个字符串中,它在字符串的末尾留下一个逗号,它不应该是它的一部分
  • 伙计们,每个字符串之间的空格可能会在不同的命令中发生变化,它从单个空格到制表符不等,这真的让事情变得更加困难.. p.s 我只是添加了几个给定值的示例
  • @RonNuni 如果您正在寻找适用于所有这些格式的通用 sscanf 格式说明符,您可能会为您完成工作。关于 this 具体答案试图传达什么,请尝试"%s %[^,], %s",但我会认真考虑一种最稳健的方法。
  • @WhozCraig,谢谢这确实适用于大多数情况,但是每次运行时空格的数量都不同,这让我很难过,因为变量 a、b 和 c 确实没有正确初始化
【解决方案2】:

您可能知道sscanf() 的使用方式与scanf() 相同,区别在于sscanf 从字符串扫描,而scanf 从标准输入扫描。
在这个问题中,您可以指定 scanf,使用一组字符“总是跳过”,就像在 this link 中所做的那样。
由于扫描所有三个字符串有不同的约束集,因此您可以在 sscanf() 中的每个 %s 之前使用 %*[^...] 指定这些约束。

【讨论】:

    【解决方案3】:

    我对使用strtok() 持保留意见,但使用它的这段代码似乎可以满足您的需求。正如我在评论中指出的那样,示例字符串"jsr /0,0 PRTSTR" 在工作中抛出了一个扳手;它在第二个字段中有一个重要的逗号,而在其他两个示例字符串中,第二个字段中的逗号不重要。如果您需要删除尾随逗号,您可以在基于空格的拆分之后执行此操作 - 如此代码所示。第二个循环测试zap_trailing_commas() 函数,以确保它在退化情况下的行为,切换尾随逗号但不会下溢缓冲区的开头或任何可怕的事情。

    #include <stdio.h>
    #include <string.h>
    
    static void zap_trailing_commas(char *str)
    {
        size_t len = strlen(str);
        while (len-- > 0 && str[len] == ',')
            str[len] = '\0';
    }
    
    static void splitter(char *command)
    {
        char a[20], b[20], c[20];
        char *ptr = strtok(command, " \t");
        strcpy(a, ptr);
        zap_trailing_commas(a);
        ptr = strtok(NULL, " \t");
        strcpy(b, ptr);
        zap_trailing_commas(b);
        ptr = strtok(NULL, " \t");
        strcpy(c, ptr);
        zap_trailing_commas(c);
        printf("<<%s>> <<%s>> <<%s>>\n", a, b, c);
    }
    
    int main(void)
    {
        char data[][50] =
        {
            "   mov/1/1/1,0 STR{7}, r7",
            "jsr /0,0            PRTSTR",
            "mov/1/1/0,0         STRADD{5}, LASTCHAR {r3} ",
        };
    
        for (size_t i = 0; i < sizeof(data)/sizeof(data[0]); i++)
            splitter(data[i]);
    
        char commas[][10] = { "X,,,", "X,,", "X,", "X" };
        for (size_t i = 0; i < sizeof(commas)/sizeof(commas[0]); i++)
        {
            printf("<<%s>> ", commas[i]);
            zap_trailing_commas(&commas[i][1]);
            printf("<<%s>>\n", commas[i]);
        }
    
        return 0;
    }
    

    样本输出:

    <<mov/1/1/1,0>> <<STR{7}>> <<r7>>
    <<jsr>> <</0,0>> <<PRTSTR>>
    <<mov/1/1/0,0>> <<STRADD{5}>> <<LASTCHAR>>
    <<X,,,>> <<X>>
    <<X,,>> <<X>>
    <<X,>> <<X>>
    <<X>> <<X>>
    

    我还测试了一个用逗号代替 X 的变体,并且只保留了单个逗号。

    【讨论】:

      猜你喜欢
      • 2013-06-20
      • 2011-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-08
      相关资源
      最近更新 更多