【问题标题】:How to use sscanf for a string with multiple words and a number at the end如何将 sscanf 用于包含多个单词和末尾数字的字符串
【发布时间】:2016-11-08 20:21:09
【问题描述】:

假设我有以下字符串和一个布尔值:

bool numberGiven = false

"@give chocolate"

"@give white chocolate"

"@give dark chocolate"

"@give white chocolate 10"

"@give dark chocolate 2"

我想使用 sscanf 将单词一起保存在 char[] 中,并将整数分别保存为 int。

我希望该数字是可选输入。用户不必输入数字,但如果输入,布尔值“numberGiven”将变为“true”。

我需要一个 if 语句来决定是否必须将 numberGiven 设为“true”。请注意,“项目名称”可以不仅仅是两个单词。例如,可以用 Kinder Schokolade Dark Chocolate 代替黑巧克力(当然最后是可选的整数)

【问题讨论】:

    标签: c input command optional scanf


    【解决方案1】:

    Never use (s)scanf for anything。相反,请使用手写解析器。使用isdigit(来自ctype.h)扫描字符串直到到达第一个数字,然后使用strtoul 转换数字。像这样的:

    char *p = str, *q;
    while (*p && !isdigit(*p)) p++;
    if (!*p) {
        numberGiven = false;
        return;
    }
    numberGiven = true;
    q = p-1;
    while (q > str && isspace(*q) q--;
    q[1] = '\0'; /* cut off the string before the number */
    errno = 0;
    number = strtoul(p, &q, 10);
    if (q == p || *q != '\0' || errno)
       parse_error();
    

    【讨论】:

    • 次要:isdigit(*p), isspace(*q) 是 UB,有很多 *p < 0。可以使用isdigit((unsigned char) *p)
    • 对于像str = "1"q = p-1; 这样的病理输入是 UB 和 UV,可以让 OP 开始使用。
    【解决方案2】:

    假设您没有“@give 70% real chocolate 25”作为可能的字符串(即名称本身不包含数字),您似乎需要在sscanf() 中设置扫描集。

    const char *buffer = "@give white chocolate 10";
    int n_vals;
    char name[300];
    int number;
    
    n_vals = sscanf(buffer, "@%299[^0-9] %d", name, &number);
    if (n_vals == 1)
        …process string with name only (and possible trailing blanks)…
    else if (n_vals == 2)
        …process string with name and number (and probably trailing blanks)…
    else
        …malformatted buffer…
    

    如果要匹配数据(输入)字符串中的@,请将其从格式字符串中删除。如果您不想在输出字符串中使用@give,请改用"@ give %299[^0-9] %d" 作为格式字符串。

    请注意,格式字符串中的空格映射到输入数据中的可选空格。

    如果您需要处理70% 问题,那么可能是时候再考虑一下了。您可以一次扫描一个单词(有关详细信息,请参阅Using sscanf() in a loop)并确定您何时到达字符串末尾,以及最后一个字符串是否为纯数字。

    【讨论】:

      【解决方案3】:

      sscanf 不能简单地应用考虑到使用数字作为名称的情况。
      所以,请执行以下操作。

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <ctype.h>
      #include <stdbool.h>
      
      int main(void){
          char line[96];
      
          while(fgets(line, sizeof line, stdin)){
              bool numberGiven = false;
              char name[96];
              int number;
      
              if(strncmp(line, "@give ", 6) != 0){// check start with "@give "
                  printf("invalid format\n");
                  continue;
              }
              //end trim
              size_t len = strlen(line);
              char *p = &line[len-1];
              while(isspace((unsigned char)*p)){
                  *p-- = 0;
              }
      
              p = strrchr(line, ' ');//last space (last part)
              if(1 == sscanf(p, "%d", &number)){
                  numberGiven = true;
                  *p = 0;
              }
              strcpy(name, line + 6);// 6: "@give "
              if(numberGiven)
                  printf("name:%s number:%d\n", name, number);
              else
                  printf("name:%s\n", name, number);
          }
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-06-27
        • 2015-09-21
        • 1970-01-01
        • 2017-04-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多